Wednesday, December 19, 2007

St John's Wort Help With Confidence

From the name to the instance with DynamicMethod

A customer places during logging LogMessages different (different Classes) in a database. It shall state the type of message stored (LogMessage class name), the message itself as well as other fields in the table.
should now read the entries and the original objects are restored.

For this solution the obvious way with Reflection was chosen:

string s = "Namespace.Name.FromDB";
Assembly.GetAssembly Assembly a = (typeof (this class));
a.GetType Type t = (s );
base type b = (base type) Activator.CreateInstance (t);

Since this is not very performant, the code has improved as follows:

string s = "Namespace.Name.FromDB";
Assembly Assembly.GetAssembly a = (typeof (this class));
Type t = a.GetType (s);
ConstructorInfo i = t.GetConstructor (Type.EmptyTypes);
base type b = (base type) i.Invoke (null);

Where the class name and the associated ConstructorInfo in a static Dictionaire be stored so they do not have to be re-evaluated on every call. Thus we have from the second to nth call the desired performance gain. The code looks like this.

ConstructorInfo c = null;
if (_cinfo.TryGetValue (s, out c)) {

c = t.GetConstructor (Type.EmptyTypes);
lock (_cinfo)

{if (_cinfo.ContainsKey (s) )
{
_cinfo.Add (s, c);}

}}


yet elegant and much better performance you go with Dynamic Methods. The value returned by the dynamic method delegate is as previously passed the ConstructorInfo in a Dictionaire and for subsequent calls reused:

public delegate BaseType CtorDelegate ();

DynamicMethod dm = new DynamicMethod
(MyCtor ", typeof (base type), Type.EmptyTypes, typeof (base type) modules).
ILGenerator Ilgen dm.GetILGenerator = ();
ilgen.Emit (OpCodes.Newobj, t.GetConstructor (Type.EmptyTypes)); ilgen.Emit
(OpCodes.Ret) ;
CtorDelegate d = (CtorDelegate) dm.CreateDelegate (typeof (CtorDelegate));

The call is then just as short (d previously read from the Dictionnaire) and incredibly fast:

message = t (t) d ();

Now we just need everything to be beautifully packaged in a factory class and finished . More on this subject including performance measurements can be found as always with Google ;-)