 |
|
 |
HI,
I've made some test of your code into my ORM because I was having your same problem. But after some test I've notice that this solution is slower then mine. In a real application the call to SetHandler and GetHandler are made each time I need to get or set value. In your example the comparison with the reflection is done only beetween 'fieldInfo.GetValue(simpleClass)' and 'setHandler(simpleClass, "test")' but for a real comparison you need to put inside the loop cycle also the call to 'SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, fieldInfo)' because this is also a call you made each time you need to set/get value. Testing a little bit the Reflection I've discovered that the real costs is the GetProperty, GetField methods not the SetValue or GetValue. So my solution is to store in a static class that works like a cache, the PropertyInfo and FieldInfo of each businessobject of the ORM, then, when need to set/get value, acces the cache, get the PropertyInfo/FieldInfo for the requeste business object and set/get the value PropertyInfo/FieldInfo.
Change your test code in this and look at the result. The dynamic method call is really slower the Reflection.
// Main static void Main(string[] args) { Console.WriteLine("How Many Test Iterations Would You Like To Run?"); int loops = int.Parse(Console.ReadLine());
CreateObjectUsingReflection(loops); CreateObjectUsingDynamicMethodCall(loops);
SetValueUsingReflection(loops); SetValueUsingReflectionWithCache(loops); SetValueUsingDynamicMethodCall(loops);
GetValueUsingReflection(loops); GetValueUsingReflectionWithCache(loops); GetValueUsingDynamicMethodCall(loops);
Console.WriteLine("Test Complete."); Console.Read(); }
// CreateObjectUsingReflection private static void CreateObjectUsingReflection(int loops) { StartTest("Begin CreateObjectUsingReflection");
for (int i = 0; i < loops; i++) { object result = Activator.CreateInstance(type, true); }
EndTest("End CreateObjectUsingReflection"); }
// CreateObjectUsingDynamicMethodCall private static void CreateObjectUsingDynamicMethodCall(int loops) { StartTest("Begin CreateObjectUsingDynamicMethodCall");
InstantiateObjectHandler instantiateObjectHandler = DynamicMethodCompiler.CreateInstantiateObjectHandler(type);
for (int i = 0; i < loops; i++) { object result = instantiateObjectHandler(); }
EndTest("End CreateObjectUsingDynamicMethodCall"); }
// SetValueUsingReflection private static void SetValueUsingReflection(int loops) { StartTest("Begin SetValueUsingReflection");
for (int i = 0; i < loops; i++) { fieldInfo = type.GetField("stringField", BINDING_FLAGS); fieldInfo.SetValue(simpleClass, "test"); }
EndTest("End SetValueUsingReflection"); }
// SetValueUsingReflection private static void SetValueUsingReflectionWithCache(int loops) { StartTest("Begin SetValueUsingReflectionWithCache");
for (int i = 0; i < loops; i++) { fieldInfo.SetValue(simpleClass, "test"); }
EndTest("End SetValueUsingReflection"); }
// SetValueUsingDynamicMethodCall private static void SetValueUsingDynamicMethodCall(int loops) { StartTest("Begin SetValueUsingDynamicMethodCall");
for (int i = 0; i < loops; i++) { SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, fieldInfo);
setHandler(simpleClass, "test"); }
EndTest("End SetValueUsingDynamicMethodCall"); }
// GetValueUsingReflection private static void GetValueUsingReflection(int loops) { StartTest("Begin GetValueUsingReflection");
for (int i = 0; i < loops; i++) { fieldInfo = type.GetField("stringField", BINDING_FLAGS); string value = (string)fieldInfo.GetValue(simpleClass); }
EndTest("End GetValueUsingReflection"); }
// GetValueUsingReflection private static void GetValueUsingReflectionWithCache(int loops) { StartTest("Begin GetValueUsingReflectionWithCache");
for (int i = 0; i < loops; i++) { string value = (string)fieldInfo.GetValue(simpleClass); }
EndTest("End GetValueUsingReflection"); }
// GetValueUsingDynamicMethodCall private static void GetValueUsingDynamicMethodCall(int loops) { StartTest("Begin GetValueUsingDynamicMethodCall");
for (int i = 0; i < loops; i++) { GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, fieldInfo);
string value = (string)getHandler(simpleClass); }
EndTest("End GetValueUsingDynamicMethodCall"); }
// StartTest private static void StartTest(string message) { lastTestStartTime = DateTime.Now; Console.WriteLine(message); }
// EndTest private static void EndTest(string message) { Console.WriteLine(message); Console.WriteLine(DateTime.Now - lastTestStartTime); Console.WriteLine(""); }
|
|
|
|
 |
|
 |
I have been following your informative articles ever since I came across them. Knowing that there is still room for improvement in my codes which uses utilizes reflection for generic functions in my DAL (Monkey #2).
In that regard, since you are more knowledgeable in this matter, could you spare some time to have a look at my codes and provide on how should I tackle it in converting it to Dynamic Code Generation? Thank you so much, here is one of the functions in my DAL which consumes a generic class passed from BLL.
public T FetchOne(string sqlStatement, List whereParameters) { Type objectType = typeof(T); object businessObject = null; _dataAccess.PrepareQuery(sqlStatement, CommandType.StoredProcedure); for (int a = 0; a <= whereParameters.Count - 1; a++) { InsertWhereParameter(whereParameters[a]); } if (_dataAccess.RecordExists()) { businessObject = Activator.CreateInstance(objectType); DataRow dr = _dataAccess.GetDataRow(); for (int b = 0; b < dr.Table.Columns.Count; b++) { string columnName = dr.Table.Columns[b].ColumnName; PropertyInfo field = objectType.GetProperty(columnName); object value = dr[b]; if (!(value is System.DBNull)) field.SetValue(businessObject, dr[b], null); else field.SetValue(businessObject, null, null); } } return (T)businessObject; }
And this would be part of the function that I am using, could you help me out on how I could convert it?
Type myType = typeof(T); PropertyInfo myPropInfo = myType.GetProperty(businessObject.Fields[a].FieldName); string fieldType = string.Empty; if (myPropInfo.PropertyType.ToString().IndexOf("Nullable") > 0) fieldType = Nullable.GetUnderlyingType(myPropInfo.PropertyType.UnderlyingSystemType).ToString(); else fieldType = myPropInfo.PropertyType.ToString(); _dataAccess.AddNullParameter(businessObject.Fields[a].FieldName, fieldType);
modified on Monday, March 16, 2009 9:09 AM
|
|
|
|
 |
|
 |
Hello again,
While I was here I thought I could make some comments on Reflection.Emit and on your approach of using it to really make things more efficient. If I'm wrong some one please be kind to correct me.
The author says he uses Reflection.Emit for an ORM but his code shows getting and setting for only one field/property. When dealing with a DataReader you would normally have multiple fields and the data is read sequentially, so it wont exactly work with this code. I know the author has another article where he shows how to address that. So be sure to check it out.
Also know that Reflection.Emit is more efficient when you deal with a great amount of data or a great amout of iterations and I mean more than a couple of thousands rows. You can verify this by running the benchmark program supplied.
Hope this helps! 
|
|
|
|
 |
|
|
 |
|
 |
I'm not sure, but my guess is that it would remain in memory until the AppDomain is unloaded.
|
|
|
|
 |
|
 |
If you are using not directly Reflection.Emit but dynamicmethods, they get garbage collected. Directly from msdn's DynamicMethod Definition: Defines and represents a dynamic method that can be compiled, executed, and discarded. Discarded methods are available for garbage collection.
You can use the DynamicMethod class to generate and execute a method at run time, without having to generate a dynamic assembly and a dynamic type to contain the method. The executable code created by the just-in-time (JIT) compiler is reclaimed when the DynamicMethod object is reclaimed. Dynamic methods are the most efficient way to generate and execute small amounts of code.
|
|
|
|
 |
|
 |
say I have function in SimpleClass.cs called as Helloworld() public string HelloWorld(string userName) { return "Welcome to the World of Dynamic Method Invokation: " + userName; }
I want to call this function dynamically by passing functionName.
Is this possible with DynamicMethod class?
Thanks, Jyothi
|
|
|
|
 |
|
 |
Here's a sample. It hasn't been tested so you may need to tweek it a bit...
Type type = typeof(SimpleClass); GetHandler handler = DynamicMethodCompiler.CreateGetHandler(type, type.GetProperty("HelloWorld");
SimpleClass simpleClass = new SimpleClass();
string value = (string)handler(simpleClass);
|
|
|
|
 |
|
 |
Yes I worked on it and able to call a method dynamically using DynamicMethod class TheCode follows here:
private static SimpleClass simpleClass = SimpleClass.CreateInstance(); private static Type type = typeof(SimpleClass); DynamicMethod dynamicGet = new DynamicMethod("DynamicGet" typeof(object), new Type[] { typeof(object) }, type, true); ILGenerator getGenerator = dynamicGet.GetILGenerator();
getGenerator.Emit(OpCodes.Ldarg_0); getGenerator.Emit(OpCodes.Call, type.GetMethod("HelloWorld")); if(type.IsValueType) { getGenerator.Emit(OpCodes.Box, type); } getGenerator.Emit(OpCodes.Ret); GetHandler getHandler = (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler)); string value = (string)getHandler(simpleClass);
but I want to pass 'username' as String parameter to the method "HelloWorld(string userName)"
how to achieve this?
|
|
|
|
 |
|
 |
Sorry, I misunderstood the original question . If you want to be able to call a method instead of a property/field you will have to make a few modifications. First, you'll need to add a new delegate
public delegate object MethodHandler(object source, string param1);
Then you'd need a method similar to the following (this is untested code, but should be close)
internal static MethodHandler CreateMethodHandler(Type type, MethodInfo methodInfo) { DynamicMethod dynamicGet = CreateGetDynamicMethod(type); ILGenerator methodGenerator = dynamicGet.GetILGenerator();
methodGenerator.Emit(OpCodes.Ldarg_0); methodGenerator.Emit(OpCodes.Ldarg_1); methodGenerator.Emit(OpCodes.Call, methodInfo); BoxIfNeeded(methodInfo.ReturnType, methodGenerator); methodGenerator.Emit(OpCodes.Ret);
return (MethodHandler)dynamicGet.CreateDelegate(typeof(MethodHandler)); }
|
|
|
|
 |
|
 |
Really great article! I'm amazed and impressed you were able to accomplish so much with a "very limited understanding of IL" (your words). Well done!
Some enhancements you or your readers may add to the Compiler: 1. Support a constructor delegate which accepts arguments as an object[]. 2. Detect when the constructed type is a ValueType, and generate code to box a zero-initialized local variable (for a 0-argument constructor). 3. Detect when the field or property is static, and generate code to correctly access the item, ignoring the 'source' argument. 4. Create overloads of CreateGet/SetHandler methods which accept a string, the name of the field or property to access, which uses reflection to find the FieldInfo or PropertyInfo.
Or hire me to do it.
modified on Wednesday, August 27, 2008 5:42 PM
|
|
|
|
 |
|
 |
Hi, your article was extremely helpful in helping me boosting performance with my reflection routine.
There's one small oddity i found while using your code and this only not apparent until in debugging mode
What I wanted to do was to create an object handler based on decimal type by writing code such as this....
DynamicMethodCompiler.InstantiateObjectHandler instantiateObjectHandler = DynamicMethodCompiler.CreateInstantiateObjectHandler(typeof(decimal));
Then, on the first line inside CreateInstantiateObjectHandler()..
ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
GetConstructor() returns a null reference... this means it wasn't able to find any default constructor at all. Furthermore, GetConstructor will always return null for all Value types like string, int32, bool and etc..
|
|
|
|
 |
|
 |
E! Ray K wrote: GetConstructor() ... wasn't able to find any default constructor at all [for the decimal ValueType].
That's correct. ValueTypes don't have actual zero-argument constructor methods. In fact, they aren't allowed by the CLS. The CLI allows it I think, but many languages do not. E.g. try declaring a structure in C# with an explicit 0-arg constructor. Not allowed! When you write code using the default constructor, what's really going on under the hood is not a newobj method call, but initobj, which zeros out all fields in the instance.
MyStruct value = new MyStruct(); ldloca value initobj MyStruct
The solution here is to modify CreateInstantiateObjectHandler() to detect when its type is a ValueType. The generated method will need a local variable of that type and use a box operation to create a boxed instance. That is, for a ValueType it will generate a method body equivalent to this:
.locals init ([0] MyStruct dummy) ldloc dummy box MyStruct ret
The implementation is left as an excercise to the reader. 
|
|
|
|
 |
|
 |
I have implemented the above as suggested. Here is the code if anyone is interested:
private static InstantiateObjectHandler CreateStructInstantiateHandler(Type type) { DynamicMethod dynamicMethod = new DynamicMethod("InstantiateObject", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, type, true); dynamicMethod.InitLocals = true; ILGenerator generator = dynamicMethod.GetILGenerator(); LocalBuilder local = generator.DeclareLocal(type); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Box, type); generator.Emit(OpCodes.Ret); return (InstantiateObjectHandler)dynamicMethod.CreateDelegate(typeof(InstantiateObjectHandler)); }
|
|
|
|
 |
|
 |
Hi, your code works perfectly for me on the server, however I have a client where I can't use the same constructor that you use.
I'm only able to use the following constructor:
DynamicMethod(String, Type, Type[])
The problem is that the generated delegate crashes, and I think it doesn't know the type of the object being set.
Do you know what modifications would be required to get this to work with this constructor?
Thanks.
|
|
|
|
 |
|
 |
I'd love to give you a hand. Can you tell me which method of DynamicMethodComplier you're trying to use? And maybe provided a code snipet of what you're trying to get it to do? I'm not quite clear what you mean when you say you can only call DynamicMethod(String, Type, Type[]). Why aren't you able to pass in any of the other flags to the constructor? Some of them are pretty important to making the code run.
|
|
|
|
 |
|
 |
I'm using the code from this article exactly as you have it, but I'm using Microsoft's SilverLight 2.0 Beta 1 as the client, and for security reasons(of which I'm unsure), they don't allow the other constructors.
I don't know how possible it is to make your code work without the other flags, but I thought you would be the first person to ask. I don't mean to have you do my work for me, but I'm not sure how the lack of these parameters affect the IL code, and any type changing that may be needed.
Thanks.
|
|
|
|
 |
|
 |
Interesting. I haven't tried using this method in Silverlight yet. I could see how there could be some issues with it, but if I get some time I'll mess around with it.
|
|
|
|
 |
|
|
 |
|
 |
The reason I need it so much in SL2 is that I send objects from the server(in XML), and I have to hydrate them on the client. In SilverLight, you can ONLY populate the datagrid with objects.
For now, we're only going to use paged queries from the server, because populating a lot of objects sit reflection is UGLY(read slow, lol).
|
|
|
|
 |
|
 |
I finally had some time to look into this. The key missing piece for using this in Silverlight is that last parameter... skipVisibility = true. The "skipVisibility" parameter is the one that tells the clr to ignore standard visibility rules (i.e. public, private, etc.) so that it's ok to get/set the values of private fields and properties. This means that, while you are still able to use dynamic IL generation inside of Silverlight, it will only work on fields/properties/methods that are flagged as public.
That being said, I would get some benchmarks on hydrating your objects via reflection before you throw that idea out. I've used that approach many times with reasonable success. The key is knowing which parts of reflection are slow and which parts are REALLY slow. It turns out that getting/setting field values isn’t the part that kills you. The really slow part is finding the correct System.Reflection.FieldInfo object. If you can find a way to only search for the FieldInfo object once and then store that value away for each subsequent request, you can get a pretty reasonably performant application. I've used that solution on several projects with great success.
|
|
|
|
 |
|
 |
By the way, when I use the shorter constructor, the delegate does get created properly, but crashes when I use it.
I think one of the operations is probably invalid in this case, but I'm not sure.
|
|
|
|
 |
|
 |
Since you are using the .NET 2.0 framework I find it rather annoying that some stuff isn't used.
A sealed class with only a private constructor? You do know that .NET 2.0 introduced the static modifier for classes?
Generics? object GetHandler(object source)... I'm sure you could easily generate a generic delegate, something like TValue GetHandler<TValue, TObject>(TObject source) which would at least give a much better performace for value types. Using generics would also give the extra advantage of not needing to pass the type as a parameter 
And I'm not sure why the actual methods are declared as internal 
It's still an awesome class though, just what I needed to get me started on this little thing I'm working on, so you get my 5!
|
|
|
|
 |
|
 |
Thanks for the feedback. I've just recently learned about the new Static class modifier. I've been converting classes in my source code as I find them. I just haven't updated this article with those changes yet.
The problem with Generics is that they don't really work in the scenarios this was built for. For example, if you know the type of class you want to instantiate at design time, you would most likely instantiate it directly (i.e. SimpleClass simpleClass = new SimpleClass()). I think the same thing would apply for Gets and Sets as well. If that’s not true, I could add an overload that would support Generics. If this would be helpful to anyone, let me know and I’ll update the code.
As far as “internal” goes, that just happens to be the way it’s used in the application I pulled this code from. Sorry, but at least it’s an easy change
|
|
|
|
 |
|
 |
But, the point is, either way, at one point, you will need to know the type. You pulled it out of the library, which just forces the ugliness of reflection onto the end-user. Using generic, we can rewrite SetValueUsingDynamicMethodCall as
private static void SetValueUsingDynamicMethodCall2(int loops) { StartTest("Begin SetValueUsingDynamicMethodCall2");
SetHandler setHandler = DynamicMethodCompiler.CreateFieldSetHandler(simpleClass, "stringField"); for (int i = 0; i < loops; i++) { setHandler(simpleClass, "test"); }
EndTest("End SetValueUsingDynamicMethodCall2"); }
Note that no reflection is performed in the end-user code. All that is needed is a object to be worked on, and the name of the field. CreateFieldSetHandler is defined as this:
static SetHandler CreateFieldSetHandler(T t, string fieldName) { FieldInfo fieldInfo = typeof(T).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); DynamicMethod dynamicSet = CreateSetDynamicMethod(typeof(T)); ILGenerator setGenerator = dynamicSet.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0); setGenerator.Emit(OpCodes.Ldarg_1); UnboxIfNeeded(fieldInfo.FieldType, setGenerator); setGenerator.Emit(OpCodes.Stfld, fieldInfo); setGenerator.Emit(OpCodes.Ret);
return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler)); }
Truth, James
|
|
|
|
 |