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 ).
Rectangle.cs : Operations will take in place.
Square.cs : Operations will take in place.
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.
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) :)
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:
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.
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.
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
Post a Comment