a study about Reflection Class for C# programmer

Reflection provides objects (of type Type) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties ( thanks to Microsoft for the definition  Ref: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/reflection ).

I prepare sort of codes to make Reflection approach closer to you :)

Here are the keywords to be mentioned in the study:
  • Load Assembly, Initiate Class then invoke method(s) with/out parameters - Beginner Level
  • Load Class and Invoke method through Type Def. (string name) with parameters - Beginner Level
  • Suppress cast (convert) operation for incompatible classes with Reflection - Intermediate Level
  • Anonymous Type calls via Reflection - Advance Level

First of all, I would like to describe all classes to be used in the lab. I am going to play with Mathematics mainly Geometry.

IShape.cs : Interface of the shape class.



namespace MathematicsForReflectionScenarios
{
    public interface IShape
    {
        int ColorCode { get; set; }
    }
}


Shape.cs : Rests class are going to be inherited from Because, I want to generate bad conversion from one class 2 other class without Reflection.


namespace MathematicsForReflectionScenarios
{
    public class Shape : IShape
    {
        private int colorCode=-1;
        public int ColorCode { get { return colorCode; } set { colorCode = value; } }

        public int Area()
        {
            throw new NotImplementedException();
        }

        public int Perimeter()
        {
            throw new NotImplementedException();
        }
    }
}

Rectangle.cs : Operations will take in place.


namespace MathematicsForReflectionScenarios
{
    public sealed class Rectangle : Shape
    {
        int height;
        int weight;
        public Rectangle()
        {

        }

        public Rectangle(int Height, int Weight)
        {
            height = Height;
            weight = Weight;
        }

        public new int Area()
        {
            return height * weight;
        }

        public new int Perimeter()
        {
            return 2 * (weight + height);
        }

        public int customArea(int Height, int Weight)
        {
            return Height * Weight;
        }

        public int customPerimeter(int Height, int Weight)
        {
            return 2 * (Height + Weight);
        }
    }
}

Square.cs : Operations will take in place.



namespace MathematicsForReflectionScenarios
{
    public sealed class Square : Shape
    {
        int side;
        public Square()
        {

        }

        public Square(int Side)
        {
            side = Side;
        }

        public new int Area()
        {
            return side * side;
        }
        public new int Perimeter()
        {
            return 4 * side;
        }

        public int customArea(int Side)
        {
            return Side * Side;
        }

        public int customPerimeter(int Side)
        {
            return 4 * Side;
        }
    }
}


It was compiled and built so "MathematicsForReflectionScenarios.dll" is generated. 

According to above design, Let's start our journey.

Scenario 1:
- Load library
- Initiate Rectangle class 
- Invoke Method with/out Parameters for Rectangle
- Write the returning value of method to the Console.




 // Load the library from file
 Assembly assembly = Assembly.LoadFrom("MathematicsForReflectionScenarios.dll");
 MethodInfo methodInfo = null;
 object result = null;

 //Rectangle
 Console.WriteLine("Rectangle ----------");
 Type type = assembly.GetType("MathematicsForReflectionScenarios.Rectangle");
 if (type != null)
 {
     // Create a constructor for the Rectangle class.
     // Rectangle class already takes two parameters : Height (int) and Width (int) so
     // create Type[] array for each parameter seperately
     ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(int), typeof(int) });

     // Initate the class with 4 and 7
     object instance = constructor.Invoke(new object[] { 4, 7 });
     try
     {
         // sample of a method call without parameter
         methodInfo = type.GetMethod("Area");
         result = methodInfo.Invoke(instance, null);
         // Write the result to the output channel
         Console.WriteLine("Area Method = " + result.ToString());

         // sample of a method call without parameter
         methodInfo = type.GetMethod("Perimeter");
         result = methodInfo.Invoke(instance, null);
         // Write the result to the output channel
         Console.WriteLine("Perimeter Method = " + result.ToString());

         // sample of a method call with parameter
         object[] parametersArray = new object[] { 3, 8 };
         methodInfo = type.GetMethod("customArea");
         result = methodInfo.Invoke(instance, parametersArray);
         // Write the result to the output channel
         Console.WriteLine("customArea Method = " + result.ToString());

         // sample of a method call with parameter
         parametersArray = new object[] { 3, 8 };
         methodInfo = type.GetMethod("customPerimeter");
         result = methodInfo.Invoke(instance, parametersArray);
         // Write the result to the output channel
         Console.WriteLine("customPerimeter Method = " + result.ToString());
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }
 }

It is time to make situation complex.
Suppose that we have a method and we send Rectangle class than cast it to the Square which should throw error (Cast mismatch) :)


namespace PlayWithReflection
{
    class Program
    {
        public Shape moveColorCodeTo1 (Shape shape)
        {
            Assembly assembly = Assembly.LoadFrom("MathematicsForReflectionScenarios.dll");
            Type type = assembly.GetType(shape.GetType().ToString());
            ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(int), typeof(int) });
            object instance = constructor.Invoke(new object[] { 4, 7 });
            PropertyInfo propInfo = type.GetProperty("ColorCode");


            propInfo.SetValue(instance, 1);

            return (Shape)instance;
        }
        static void Main(string[] args)
        {
            Program prg = new Program();
                
            Rectangle rec = new Rectangle(1, 2);
            rec.ColorCode = 0;
            Console.WriteLine("Reflaction : Dynamic Invoke parameter and return objects are different classes Rectangle to Square ----------");
            Square s = (Square)prg.moveColorCodeTo3(rec);
            Console.WriteLine("Color Code = " + s.ColorCode.ToString());
        }
    }
}


Let's see how are we going to invoke properties and methods of Anonymous Type. We define Circle type and call methods as well as properties:



namespace PlayWithReflection
{
    class Program
    {
        public object CircleClassOnTheFly()
        {
             var Circle = new
            {
                shape = new Shape() ,
                radious = -1,
                pi = -1,
                Area = new Func<int>(() => { return (2 * 4 * 4); }),
                Perimeter = new Func<int>(() => { return (2 * 3 * 4); })
            };
            Assembly assembly = Assembly.LoadFrom("MathematicsForReflectionScenarios.dll");
            Type type = Circle.GetType();
            ConstructorInfo constructor = type.GetConstructors()[0];
            object instance = constructor.Invoke(new object[] { new Shape() { ColorCode = 1 } , 4 , 3, Circle.Area, Circle.Perimeter });

            return instance;
        }
        static void Main(string[] args)
        {
           Program prg = new Program();
                
           MethodInfo methodInfo = null;
           object result = null;
Console.WriteLine("Reflaction : Circle class through generic type ----------");
           var genericClass = prg.CircleClassOnTheFly();
           type = genericClass.GetType();
           foreach(PropertyInfo prop in type.GetProperties())
           {
               object instanceTemp = prop.GetValue(genericClass);
               Type propType = prop.GetValue(genericClass).GetType();
                                   
               if (propType.GetProperties().Length > 0) // property is a reference to another class or struct
               {
                   foreach (PropertyInfo pInfo in propType.GetProperties())
                   {
                       if (pInfo.Name == "Method")
                       {
                           methodInfo = (MethodInfo)pInfo.GetValue(instanceTemp);
                           Func<int> converted = (Func<int>) Delegate.CreateDelegate(pInfo.ReflectedType, null, methodInfo);
                           Console.WriteLine(prop.Name + " Method = " + converted().ToString());

                       }
                       else
                           if (pInfo.Name != "Target")
                               Console.WriteLine(pInfo.Name + " = " + pInfo.GetValue(instanceTemp));
                   }
               }
               else
               {
                   Console.WriteLine(prop.Name + " = " + prop.GetValue(genericClass).ToString());
               }           
   }
 }
}




Here is the source code, download it, debug it, play it !

https://github.com/TheMaty/PlayWithReflection

I do not have any chance to consider the approach from performance perspective. But I will update the article if I have something on that.


Enjoy.




Comments

Popular posts from this blog

Complex Query in QueryExpression in Microsoft CRM 2011

Exception caught instantiating TERADATA report server extension SQL Reporting Services

Microsoft Power Apps Portal integration with Dynamics 365 CE On-Premise - Step By Step Guide