The method in different assembly is invoked using delegate. Below is the implementation of static class FastMethodInvoker (we actually generate IL specific code):
The usage is simple:public delegate object FastInvokeHandler(object _target, object[] _params); /// <summary> /// A class to invoke methods (DynamicMethod mechanism). /// </summary> public static class FastMethodInvoker { /// <summary> /// Invokes method. /// </summary> /// <param name="_target">Instance of target object.</param> /// <param name="_sMethodName">Method name.</param> /// <param name="_params">Array of params.</param> /// <returns>Result of method.</returns> public static object InvokeMethod(object _target, string _sMethodName, object[] _params) { Type type = _target.GetType(); bool bExists = type.GetMethods().Any(t => t.Name == _sMethodName); if (!bExists) throw new ArgumentException(string.Format("Non existing method '{0}' on type '{1}'.", _sMethodName, _target.GetType().Name)); MethodInfo mi = type.GetMethod(_sMethodName); FastInvokeHandler fastInvoker = GetMethodInvoker(mi); return fastInvoker(_target, _params) ?? null; } /// <summary> /// Returns DynamicMethod. /// </summary> /// <param name="_methodInfo">MethodInfo instance.</param> /// <returns>FastInvokeHandler delegate.</returns> public static FastInvokeHandler GetMethodInvoker(MethodInfo _methodInfo) { DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] {typeof(object), typeof(object[])}, _methodInfo.DeclaringType.Module); ILGenerator il = dynamicMethod.GetILGenerator(); ParameterInfo[] ps = _methodInfo.GetParameters(); Type[] paramTypes = new Type[ps.Length]; for (int ii = 0; ii < paramTypes.Length; ii++) { if (ps[ii].ParameterType.IsByRef) paramTypes[ii] = ps[ii].ParameterType.GetElementType(); else paramTypes[ii] = ps[ii].ParameterType; } LocalBuilder[] locals = new LocalBuilder[paramTypes.Length]; for (int ii = 0; ii < paramTypes.Length; ii++) { locals[ii] = il.DeclareLocal(paramTypes[ii], true); } for (int ii = 0; ii < paramTypes.Length; ii++) { il.Emit(OpCodes.Ldarg_1); EmitFastInt(il, ii); il.Emit(OpCodes.Ldelem_Ref); EmitCastToReference(il, paramTypes[ii]); il.Emit(OpCodes.Stloc, locals[ii]); } il.Emit(OpCodes.Ldarg_0); for (int ii = 0; ii < paramTypes.Length; ii++) { if (ps[ii].ParameterType.IsByRef) il.Emit(OpCodes.Ldloca_S, locals[ii]); else il.Emit(OpCodes.Ldloc, locals[ii]); } il.EmitCall(OpCodes.Callvirt, _methodInfo, null); if (_methodInfo.ReturnType == typeof(void)) il.Emit(OpCodes.Ldnull); else EmitBoxIfNeeded(il, _methodInfo.ReturnType); for (int ii = 0; ii < paramTypes.Length; ii++) { if (ps[ii].ParameterType.IsByRef) { il.Emit(OpCodes.Ldarg_1); EmitFastInt(il, ii); il.Emit(OpCodes.Ldloc, locals[ii]); if (locals[ii].LocalType.IsValueType) il.Emit(OpCodes.Box, locals[ii].LocalType); il.Emit(OpCodes.Stelem_Ref); } } il.Emit(OpCodes.Ret); FastInvokeHandler invoker = (FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler)); return invoker; } /// <summary> /// Emits the cast to reference. /// </summary> /// <param name="il">The il.</param> /// <param name="type">The type.</param> private static void EmitCastToReference(ILGenerator il, System.Type type) { if (type.IsValueType) { il.Emit(OpCodes.Unbox_Any, type); } else { il.Emit(OpCodes.Castclass, type); } } /// <summary> /// Emits the box if needed. /// </summary> /// <param name="il">The il.</param> /// <param name="type">The type.</param> private static void EmitBoxIfNeeded(ILGenerator il, System.Type type) { if (type.IsValueType) { il.Emit(OpCodes.Box, type); } } /// <summary> /// Emits the fast int. /// </summary> /// <param name="il">The il.</param> /// <param name="value">The value.</param> private static void EmitFastInt(ILGenerator il, int value) { switch (value) { case -1: il.Emit(OpCodes.Ldc_I4_M1); return; case 0: il.Emit(OpCodes.Ldc_I4_0); return; case 1: il.Emit(OpCodes.Ldc_I4_1); return; case 2: il.Emit(OpCodes.Ldc_I4_2); return; case 3: il.Emit(OpCodes.Ldc_I4_3); return; case 4: il.Emit(OpCodes.Ldc_I4_4); return; case 5: il.Emit(OpCodes.Ldc_I4_5); return; case 6: il.Emit(OpCodes.Ldc_I4_6); return; case 7: il.Emit(OpCodes.Ldc_I4_7); return; case 8: il.Emit(OpCodes.Ldc_I4_8); return; } if (value > -129 && value < 128) { il.Emit(OpCodes.Ldc_I4_S, (SByte)value); } else { il.Emit(OpCodes.Ldc_I4, value); } } }
a) Invoking some method on external DLL assembly:
... // invoke method MyMethod(string) on type MyNamespace.MyClass (MyAssembly.dll) Assembly a = Assembly.LoadFrom("MyAssembly.dll"); object instance = a.CreateInstance("MyNamespace.MyClass"); object[] args = new object[] { "some_string_argument" }; object result = FastMethodInvoker.InvokeMethod(instance, "MyMethod", args); ...
b) Invoking some method on known instance:
...
// e.g. invoke GetXml() on DataSet instance
Type type = typeof(System.Data.DataSet);
object instance = Activator.CreateInstance(type);
object result = InvokeMethod(instance, "GetXml", null);
...
As a matter of fact this mechanism is about 5x - 10x faster than regular .NET reflection.
5 comments:
Great Article
C# Training
C# Online Training
C-Sharp Training
Dot Net Training in Chennai
.Net Online Training
ASP.NET Training
ASP NET Training
Core C# Interview Questions
Dot Net Interview Questions
Great Article… I love to read your articles because your writing style is too good, its is very very helpful for all of us and I never get bored while reading your article because, they are becomes a more and more interesting from the starting lines until the end.
rpa training in bangalore | best rpa training in bangalore
RPA training in bangalore | rpa courses in bangalore
This is such a good post. One of the best posts that I\'ve read in my whole life. I am so happy that you chose this day to give me this. Please, continue to give me such valuable posts. Cheers!
Python training in bangalore
Python course in pune
Python training in bangalore
Really very nice blog information for this one and more technical skills are improve,i like that kind of post.
AWS Training in Bangalore
Post a Comment