123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- using System.Reflection;
- using System.Reflection.Emit;
- namespace PlcSiemens.Core.Common
- {
- /// <summary>A dynamic delegate factory.
- /// </summary>
- public class DelegateFactory
- {
- /// <summary>Creates a delegate from the given methodInfo and parameterTypes.
- /// </summary>
- /// <typeparam name="D"></typeparam>
- /// <param name="methodInfo"></param>
- /// <param name="parameterTypes"></param>
- /// <returns></returns>
- public static D CreateDelegate<D>(MethodInfo methodInfo, Type[] parameterTypes) where D : class
- {
- if (methodInfo == null)
- {
- throw new ArgumentNullException("methodInfo");
- }
- if (parameterTypes == null)
- {
- throw new ArgumentNullException("parameterTypes");
- }
- var parameters = methodInfo.GetParameters();
- var dynamicMethod = new DynamicMethod(
- methodInfo.Name,
- MethodAttributes.Static | MethodAttributes.Public,
- CallingConventions.Standard,
- methodInfo.ReturnType,
- parameterTypes,
- typeof(object),
- true)
- {
- InitLocals = false
- };
- var dynamicEmit = new DynamicEmit(dynamicMethod);
- if (!methodInfo.IsStatic)
- {
- dynamicEmit.LoadArgument(0);
- dynamicEmit.CastTo(typeof(object), methodInfo.DeclaringType);
- }
- for (int index = 0; index < parameters.Length; index++)
- {
- dynamicEmit.LoadArgument(index + 1);
- dynamicEmit.CastTo(parameterTypes[index + 1], parameters[index].ParameterType);
- }
- dynamicEmit.Call(methodInfo);
- dynamicEmit.Return();
- return dynamicMethod.CreateDelegate(typeof(D)) as D;
- }
- private class DynamicEmit
- {
- private ILGenerator _ilGenerator;
- private static readonly Dictionary<Type, OpCode> _converts = new Dictionary<Type, OpCode>();
- static DynamicEmit()
- {
- _converts.Add(typeof(sbyte), OpCodes.Conv_I1);
- _converts.Add(typeof(short), OpCodes.Conv_I2);
- _converts.Add(typeof(int), OpCodes.Conv_I4);
- _converts.Add(typeof(long), OpCodes.Conv_I8);
- _converts.Add(typeof(byte), OpCodes.Conv_U1);
- _converts.Add(typeof(ushort), OpCodes.Conv_U2);
- _converts.Add(typeof(uint), OpCodes.Conv_U4);
- _converts.Add(typeof(ulong), OpCodes.Conv_U8);
- _converts.Add(typeof(float), OpCodes.Conv_R4);
- _converts.Add(typeof(double), OpCodes.Conv_R8);
- _converts.Add(typeof(bool), OpCodes.Conv_I1);
- _converts.Add(typeof(char), OpCodes.Conv_U2);
- }
- public DynamicEmit(DynamicMethod dynamicMethod)
- {
- this._ilGenerator = dynamicMethod.GetILGenerator();
- }
- public DynamicEmit(ILGenerator ilGen)
- {
- this._ilGenerator = ilGen;
- }
- public void LoadArgument(int argumentIndex)
- {
- switch (argumentIndex)
- {
- case 0:
- this._ilGenerator.Emit(OpCodes.Ldarg_0);
- break;
- case 1:
- this._ilGenerator.Emit(OpCodes.Ldarg_1);
- break;
- case 2:
- this._ilGenerator.Emit(OpCodes.Ldarg_2);
- break;
- case 3:
- this._ilGenerator.Emit(OpCodes.Ldarg_3);
- break;
- default:
- if (argumentIndex < 0x100)
- {
- this._ilGenerator.Emit(OpCodes.Ldarg_S, (byte)argumentIndex);
- }
- else
- {
- this._ilGenerator.Emit(OpCodes.Ldarg, argumentIndex);
- }
- break;
- }
- }
- public void CastTo(Type fromType, Type toType)
- {
- if (fromType != toType)
- {
- if (toType == typeof(void))
- {
- if (!(fromType == typeof(void)))
- {
- this.Pop();
- }
- }
- else
- {
- if (fromType.IsValueType)
- {
- if (toType.IsValueType)
- {
- this.Convert(toType);
- return;
- }
- this._ilGenerator.Emit(OpCodes.Box, fromType);
- }
- this.CastTo(toType);
- }
- }
- }
- public void CastTo(Type toType)
- {
- if (toType.IsValueType)
- {
- this._ilGenerator.Emit(OpCodes.Unbox_Any, toType);
- }
- else
- {
- this._ilGenerator.Emit(OpCodes.Castclass, toType);
- }
- }
- public void Pop()
- {
- this._ilGenerator.Emit(OpCodes.Pop);
- }
- public void Convert(Type toType)
- {
- this._ilGenerator.Emit(_converts[toType]);
- }
- public void Return()
- {
- this._ilGenerator.Emit(OpCodes.Ret);
- }
- public void Call(MethodInfo method)
- {
- if (method.IsFinal || !method.IsVirtual)
- {
- this._ilGenerator.EmitCall(OpCodes.Call, method, null);
- }
- else
- {
- this._ilGenerator.EmitCall(OpCodes.Callvirt, method, null);
- }
- }
- }
- }
- }
|