C# Reflection

It's about two and a half years since I'vestarted using .NET. Maybe I can say that I know it very well. I am nowconvinced that the only real advantage of .NET, if we compare it toJava, is in the existence of metadata, IL and Reflection.Emit, but veryfew programmers are willing or capable to go there. So let me presentthe example where we can use Reflection and Reflection.Emit to dosomething interesting.

Light non-trivial introductory example of reusability

There's a possibility that we need to add somefunctionality to the existing library but we are not in a position tochange that library. One possible reason why we can't change thatlibrary could be that such a library is copyright protected. So wecan't rely on our knowledge of IL and reengineer it. Luckily there is away to achieve our goals and leave that library in its current shape.Our example is an arithmetic tree. The purpose of arithmetic tree is tobuild OO representation of arithmetic expression. Its structure is abinary tree where leaf nodes represent numeric values and other nodesrepresent operators. We have two types of nodes – operators and numbersand they are instances of different classes. So we are dealing with anon-trivial example. Very nice example of arithmetic tree is presentedin article Polymorphism in C++ by Bartosz Milewski, naturally it waswritten in C++ and we will have to translate it to C#.

public abstract class ArithmeticNode
{
public abstract double Calculate();
}
public class NumericNode:ArithmeticNode
{
double _num;
public NumericNode(double num){_num = num;}
public override double Calculate()
{
return _num;
}
}
public abstract class BinaryNode:ArithmeticNode
{
protected ArithmeticNode _Left;
protected ArithmeticNode _Right;
public BinaryNode(ArithmeticNode mLeft, ArithmeticNode mRight)
{
_Left = mLeft;
_Right = mRight;
}
}
public class AddNode:BinaryNode
{
public AddNode(ArithmeticNode mLeft,
ArithmeticNode mRight):base(mLeft, mRight){}
public override double Calculate()
{
return _Left.Calculate() + _Right.Calculate();
}
}
public class MultiplyNode:BinaryNode
{
public MultiplyNode(ArithmeticNode mLeft,
ArithmeticNode mRight):base(mLeft, mRight) {}
public override double Calculate()
{
return _Left.Calculate() * _Right.Calculate();
}
}
public class DeductNode:BinaryNode
{
public DeductNode(ArithmeticNode mLeft,
ArithmeticNode mRight):base(mLeft, mRight){}
public override double Calculate()
{
return _Left.Calculate() – _Right.Calculate();
}
}
public class DivideNode:BinaryNode
{
public DivideNode(ArithmeticNode mLeft,
ArithmeticNode mRight):base(mLeft, mRight){}
public override double Calculate()
{
return _Left.Calculate() / _Right.Calculate();
}
}

As we can see we have hierarchy of classes andone very elegant idea which is unfortunately not mine, I justtranslated it to C#. To build such a tree we usually produce some kindof parser, but to make things simple we will skip parser and build itmanually, like this :

ArithmeticNode n1 = new AddNode(new NumericNode(1.0), new NumericNode(2.0));
ArithmeticNode n2 = new MultiplyNode(n1, new NumericNode(3.0));
double x = n2.Calculate ();

That would be (1 + 2) * 3. With tree comesfree recursion and to find out what is the result we just need to callCalculate method of the root node.

Now imagine that we are assigned to a projectwhere we should make simple arithmetic calculator. So we need parserand GUI and we may use that library, lets imagine that library is freeor that we will acquire license to use it. Unfortunately, specificationsays that arithmetic tree must print arithmetic expression. Sinceclasses are not sealed we can make them visitable and use Visitorpattern. So we will inherit from each class and add accept method.

Just in time inheritance

Repetitive task of extending all classes andadding accept method is boring so we will automate it. Even better, wewill use Reflection.Emit and extend dynamically only when and what isneeded. To make invocation easier we will use interface. That was theproject plan and now we can write the code. After few minutes thecoding is done (OK I had something similar already written) and this isthe code :

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
public interface IVisitable
{
void Accept(IVisitor v);
}
public interface IVisitor
{
void Visit(IVisitable v);
}
public class VisitableWrapper
{
static System.Collections.Hashtable _assembliesHolder =
System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
IVisitable _instance;

public object Current
{
get{
return _instance;
}
set{
_instance = build(value);
}
}
IVisitable build(object current)
{
Type restype;
IVisitable result;
Type currentType = current.GetType();
string theName = "Visitable" + currentType.Name;
if(!_assembliesHolder.ContainsKey(theName)){
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = theName;
ILGenerator methodIL;
MethodBuilder mb;
AssemblyBuilder assembly =
Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder module = assembly.DefineDynamicModule(theName+".dll");
TypeBuilder visitableClass = module.DefineType(theName, TypeAttributes.Public);
visitableClass.SetParent(currentType);
visitableClass.AddInterfaceImplementation(typeof(IVisitable));
Type[] arg = new Type[0];
ConstructorBuilder cb = visitableClass.DefineConstructor(MethodAttributes.Public,
CallingConventions.Standard,null);
ILGenerator ctorIL = cb.GetILGenerator();
ConstructorInfo bc =
currentType.GetConstructor(new Type[]{typeof(ArithmeticNode),typeof(ArithmeticNode)});
if(bc != null){
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldnull);
ctorIL.Emit(OpCodes.Ldnull);
ctorIL.Emit(OpCodes.Call, bc);
ctorIL.Emit(OpCodes.Ret);
}
else{
bc = currentType.GetConstructor(new Type[]{typeof(double)});
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldc_R8,0.0);
ctorIL.Emit(OpCodes.Call, bc);
ctorIL.Emit(OpCodes.Ret);
arg = new Type[1]{typeof(IVisitor)};
}
arg = new Type[1]{typeof(IVisitor)};
mb = visitableClass.DefineMethod("Accept",
MethodAttributes.Public|MethodAttributes.NewSlot|MethodAttributes.HideBySig|
MethodAttributes.Final|MethodAttributes.Virtual,
typeof(void),arg);
methodIL = mb.GetILGenerator();
ParameterBuilder paramBuilder =
mb.DefineParameter(1,ParameterAttributes.None,"v");
methodIL.DeclareLocal(typeof(object[]));
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Callvirt,(new object().GetType()).GetMethod("GetType"));
methodIL.Emit(OpCodes.Ldstr,"Visit");
methodIL.Emit(OpCodes.Ldc_I4,0×100);
methodIL.Emit(OpCodes.Ldnull);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldc_I4_1);
methodIL.Emit(OpCodes.Newarr,(new object()).GetType());
methodIL.Emit(OpCodes.Stloc_0);
methodIL.Emit(OpCodes.Ldloc_0);<

br /> me
thodIL.Emit(OpCodes.Ldc_I4_0);
methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Stelem_Ref);
methodIL.Emit(OpCodes.Ldloc_0);
methodIL.Emit(OpCodes.Callvirt,
typeof(System.Type).GetMethod("InvokeMember",
new Type[]{typeof(string),typeof(BindingFlags),typeof(Binder),
typeof(object),typeof(object[])}));
methodIL.Emit(OpCodes.Pop);
methodIL.Emit(OpCodes.Ret);
restype=visitableClass.CreateType();
result = (IVisitable)Activator.CreateInstance(restype);
_assembliesHolder.Add(theName,result);
}
else{
result = (IVisitable)_assembliesHolder[theName];
restype = result.GetType();
}
FieldInfo[] fields = currentType.GetFields(BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static );
for(int i = 0;i < fields.Length;i++){
fields[i].SetValue(result,fields[i].GetValue(current));
}
return result;
}
public void Accept(IVisitor v)
{
_instance.Accept(v);
}
}

As simple as that. Whatever other kind of nodeis added in the future to hierarchy, under the condition that it usesthe prescribed constructor signature, it will work on it too. Interfaceis the same as I used in the article about Visitor (please use Google Idon't have a link). If you're now wondering how I'm going to useVisitor on protected field, don't worry, Reflection will give us accessto non-public fields. Here is the code for the Visitor and test :

using System;
using System.Reflection;
class driver{
static void Main ()
{
ArithmeticNode n1 = new DeductNode(new NumericNode(18.0), new NumericNode(11.0));
ArithmeticNode n2 = new MultiplyNode(n1, new NumericNode(2.0));
ArithmeticNode n3 = new DivideNode(new NumericNode(36.0),new NumericNode(6.0));
ArithmeticNode n4 = new AddNode(n2, n3);
double x = n4.Calculate ();
VisitableWrapper vis = new VisitableWrapper();
vis.Current = n4;
Visitor v =new Visitor();
vis.Accept(v);
System.Console.WriteLine(" = {0}",x);
}
}
class Visitor:IVisitor
{
public void Visit(IVisitable ve)
{
if(ve is BinaryNode){
System.Console.Write("(");
VisitableWrapper temp = new VisitableWrapper();
temp.Current = ve.GetType().GetField("_Left",
BindingFlags.NonPublic |
BindingFlags.Instance).GetValue( ve );
temp.Accept(this);
switch(ve.GetType().ToString())
{
case "VisitableAddNode" : System.Console.Write(" + ");break;
case "VisitableMultiplyNode" : System.Console.Write(" * ");break;
case "VisitableDeductNode" : System.Console.Write(" – ");break;
case "VisitableDivideNode" : System.Console.Write(" / ");break;
}
temp.Current = ve.GetType().GetField("_Right",
BindingFlags.NonPublic |
BindingFlags.Instance).GetValue( ve );
temp.Accept(this);
System.Console.Write(")");
}
else
System.Console.Write(((NumericNode)ve).Calculate());
}
}

Maybe not very elegant, but it works and itsvery RAD. Yes, try this at home and all code in this article comeswithout any kind of warranty.Now probably comes the question why we must use Visitor. For printingonly we can leave it out, but tomorrow we may expect a request for XMLserializable arithmetic tree or who knows what and then we will behappy to have Visitor. See it as quick-fix framework.What if classes in hierarchy were sealed? Then we must do differently.The source of the problem is that we have no access to protected fieldsof BinaryNode. To gain access we may do something like this :

using System;
using System.Reflection;

class GoodBinaryNode
{
BinaryNode _target;
Type targetType;
public GoodBinaryNode(BinaryNode target)
{
_target=target;
targetType = target.GetType();
}
public ArithmeticNode Left
{
get
{
FieldInfo _LeftInfo = targetType.GetField("_Left",
BindingFlags.NonPublic |
BindingFlags.Instance);
return (ArithmeticNode)_LeftInfo.GetValue( _target );
}
}
public ArithmeticNode Right
{
get
{
FieldInfo _RightInfo = targetType.GetField("_Right",
BindingFlags.NonPublic |
BindingFlags.Instance);
return (ArithmeticNode)_RightInfo.GetValue( _target );
}
}
public double Calculate()
{
return _target.Calculate();
}
public void Print()
{
System.Console.Write("(");
if(Left is BinaryNode)
{
GoodBinaryNode temp = new GoodBinaryNode((BinaryNode)Left);
temp.Print();
}
else
{
System.Console.Write(Left.Calculate());
}

switch(targetType.ToString())
{
case "AddNode" : System.Console.Write(" + ");break;
case "MultiplyNode" : System.Console.Write(" * ");break;
case "DeductNode" : System.Console.Write(" – ");break;
case "DivideNode" : System.Console.Write(" / ");break;
}

if(Right is BinaryNode)
{
GoodBinaryNode temp = new GoodBinaryNode((BinaryNode)Right);
temp.Print();
}
else
{
System.Console.Write(Right.Calculate());
}
System.Console.Write(")");
}
}
class driver
{
static void Main ()
{
ArithmeticNode n1 = new DeductNode(new NumericNode(18.0), new NumericNode(11.0));
ArithmeticNode n2 = new MultiplyNode(n1, new NumericNode(2.0));
ArithmeticNode n3 = new DivideNode(new NumericNode(36.0),new NumericNode(6.0));
ArithmeticNode n4 = new AddNode(n2, n3);
double x = n4.Calculate ();
GoodBinaryNode printRoot = new GoodBinaryNode((BinaryNode)n4);
printRoot.Print();
System.Console.WriteLine(" = {0}",x);
}
}

It resembles Decorator pattern a little and ismuch easier to code than that Visitor example, only if we have to passinstance of it to some method which expects one of original hierarchytypes then we are in trouble. But then we are in trouble anyway.Naturally, we will skip Reflection.Emit exercise-we need to code onlyone class. It is much easier to write code in IL than to useReflection.Emit.

Isn't that against OO principles to try togain access to fields or methods which are not meant to be accessedfrom outside? Yes it is, if somebody makes fields inaccessible therecould be reason for that, but if it helps me to write less code then Iwill defend myself with reusability argument. A bit of creative hacking(that kind of hacking which won't make public prosecutor interested inyour activities) is always helpful.I can't remember any more good questions, if you have any, my e-mail isbelow.

Conclusion

As I demonstrated, Reflection andReflection.Emit may be used to achieve interesting things. Naturally,we need to know IL to use Reflection.Emit. Possible areas where itcould be used are AOP or Coordination Contracts. So highly configurableapplications where about everything could be changed at run time arepossible if appropriate OO patterns like Chain of Responsibility areused.About two and a half years ago I went to Microsoft of South Africa(that is where I am staying, but I am not South African) to get my copyof .NET beta 1. They charged me about US$ 5 for three CDs. Today thereis .NET 1.1, which I haven't got yet. Maybe I will go again toMicrosoft of South Africa to get CDs, but this t

ime I am not in ahurry. It looks to me that .NET started to lose its breath andadvantages which it used to have over its competitors. For example,UDDI V2 API client side implementation for .NET is still in beta 1stage! Lot of things have changed in the last two and a half years andin the world of programming changes are very fast.

About Myself

Currently I'm writing for CodeNotes.http://www.codenotes.com and preparing presentation for InternationalWeb Services Conference & Exposition in Toronto, Canada on October14-16, 2003. For more info visit http://www.WowGao.com. If you have anysuggestions, questions my address is filipbulovic@mail.com, I will tryto answer.

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!