| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 | using System;using System.Collections.Generic;using System.Reflection;using System.Reflection.Emit;namespace Houdar.Core.Util.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;        }                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);                }            }        }    }}
 |