以非泛型方式调用泛型方法
以非泛型方式调用泛型方法
通过泛型方法定义具有特定类型意义的方法是常用的手段。但在某些特定情况下,例如在一些通用的框架中,直到运行时才能确定泛型类型参数,就必须通过非泛型方式来调用泛型方法。
假定有这样一个方法:
![]() public static void Add<T>(T obj, IList<T> list)
public static void Add<T>(T obj, IList<T> list)
![]() {
{
![]() list.Add(obj);
      list.Add(obj);
![]() }
}
![]() 如果想换成这样调用:
如果想换成这样调用:
![]() Add(Type type, object obj, object list);通常的方法是这样的:
Add(Type type, object obj, object list);通常的方法是这样的:
![]() void Add(Type type, object obj, object list)
void Add(Type type, object obj, object list)
![]() {
{
![]() MethodInfo mi = typeof(MyType).GetMethod("Add");
    MethodInfo mi = typeof(MyType).GetMethod("Add");
![]() MethodInfo gmi = mi.MakeGenericMethod(type);
    MethodInfo gmi = mi.MakeGenericMethod(type);
![]() gmi.Invoke(new object[] { obj, list });
    gmi.Invoke(new object[] { obj, list });
![]() }当然,除了性能上的问题,这个方案是完全可行的。但是经过测试,通过这种包装后的耗时比直接的泛型调用相差将近1000倍。因此还需要一些折中一点的方案。为此,我请教了装配脑袋。他给出了一个非常好的方案:
}当然,除了性能上的问题,这个方案是完全可行的。但是经过测试,通过这种包装后的耗时比直接的泛型调用相差将近1000倍。因此还需要一些折中一点的方案。为此,我请教了装配脑袋。他给出了一个非常好的方案:
先定义一个泛型包装委托:
![]() public delegate void GM<T>(T obj, IList<T> list);然后再定义一个非泛型包装的接口:
public delegate void GM<T>(T obj, IList<T> list);然后再定义一个非泛型包装的接口:
![]() interface ING
interface ING
![]() {
{
![]() void NGM(object obj, object list);
    void NGM(object obj, object list);
![]() }然后再实现这个接口,在实现类中直接调用传入的泛型委托:
}然后再实现这个接口,在实现类中直接调用传入的泛型委托:
![]() public class GClass<T> : ING
public class GClass<T> : ING
![]() {
{
![]() private GM<T> m_gmd;
    private GM<T> m_gmd;
![]()
![]() public GClass(GM<T> gmd)
    public GClass(GM<T> gmd)
![]() {
    {
![]() m_gmd = gmd;
        m_gmd = gmd;
![]() }
    }
![]()
![]() #region INGClass 成员
    #region INGClass 成员
![]()
![]() public void NGM(object obj, object list)
    public void NGM(object obj, object list)
![]() {
    {
![]() m_gmd((T)obj, (IList<T>)list);
        m_gmd((T)obj, (IList<T>)list);
![]() }
    }
![]()
![]() #endregion
    #endregion
![]() }然后就可以非常简单地使用已有的泛型方法来获得一个非泛型接口实现了:
}然后就可以非常简单地使用已有的泛型方法来获得一个非泛型接口实现了:
![]() static ING GetNGC(Type genericType, Type methodType, string methodName)
static ING GetNGC(Type genericType, Type methodType, string methodName)
![]() {
{
![]() MethodInfo mi = methodType.GetMethod(methodName);
    MethodInfo mi = methodType.GetMethod(methodName);
![]() MethodInfo gmi = mi.MakeGenericMethod(genericType);
    MethodInfo gmi = mi.MakeGenericMethod(genericType);
![]() Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
    Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
![]() return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
    return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
![]() }
}
![]() 通过执行所返回接口的非泛型方法来达到调用泛型方法的目的:
通过执行所返回接口的非泛型方法来达到调用泛型方法的目的:
![]() ING ng = GetNGC(typeof(int), typeof(MyType), "Add");
ING ng = GetNGC(typeof(int), typeof(MyType), "Add");
![]() ng.NGM(i, list);比对一下,耗时大约是直接泛型调用耗时的三倍。显然这个方案是一个非常实用的方案。归纳一下,一共需要四步:
ng.NGM(i, list);比对一下,耗时大约是直接泛型调用耗时的三倍。显然这个方案是一个非常实用的方案。归纳一下,一共需要四步: 
![]() using System;
using System;
![]() using System.Collections.Generic;
using System.Collections.Generic;
![]() using System.Reflection;
using System.Reflection;
![]() using System.Reflection.Emit;
using System.Reflection.Emit;
![]() using System.Text;
using System.Text;
![]()
![]() namespace GenericMethodTest
namespace GenericMethodTest
![]() {
{
![]() /// <summary>
    /// <summary>
![]() /// 接口生成器
    /// 接口生成器
![]() /// </summary>
    /// </summary>
![]() internal static class InterfaceGenerator
    internal static class InterfaceGenerator
![]() {
    {
![]() private static Random _Random = new Random();
        private static Random _Random = new Random();
![]()
![]() private static char GetRandomLetter()
        private static char GetRandomLetter()
![]() {
        {
![]() int i = (_Random.Next() % 26) + 97;
            int i = (_Random.Next() % 26) + 97;
![]() byte[] b = BitConverter.GetBytes(i);
            byte[] b = BitConverter.GetBytes(i);
![]() return BitConverter.ToChar(b, 0);
            return BitConverter.ToChar(b, 0);
![]() }
        }
![]()
![]() private static string GetRandomString(int n)
        private static string GetRandomString(int n)
![]() {
        {
![]() char[] chars = new char[n];
            char[] chars = new char[n];
![]() for (int i = 0; i < n; i++)
            for (int i = 0; i < n; i++)
![]() {
            {
![]() chars[i] = GetRandomLetter();
                chars[i] = GetRandomLetter();
![]() }
            }
![]() return new string(chars);
            return new string(chars);
![]() }
        }
![]()
![]() private static void LoadArg(ILGenerator gen, int index)
        private static void LoadArg(ILGenerator gen, int index)
![]() {
        {
![]() switch (index)
            switch (index)
![]() {
            {
![]() case 0:
                case 0:
![]() gen.Emit(OpCodes.Ldarg_0);
                    gen.Emit(OpCodes.Ldarg_0);
![]() break;
                    break;
![]() case 1:
                case 1:
![]() gen.Emit(OpCodes.Ldarg_1);
                    gen.Emit(OpCodes.Ldarg_1);
![]() break;
                    break;
![]() case 2:
                case 2:
![]() gen.Emit(OpCodes.Ldarg_2);
                    gen.Emit(OpCodes.Ldarg_2);
![]() break;
                    break;
![]() case 3:
                case 3:
![]() gen.Emit(OpCodes.Ldarg_3);
                    gen.Emit(OpCodes.Ldarg_3);
![]() break;
                    break;
![]() default:
                default:
![]() if (index < 128)
                    if (index < 128)
![]() {
                    {
![]() gen.Emit(OpCodes.Ldarg_S, index);
                        gen.Emit(OpCodes.Ldarg_S, index);
![]() }
                    }
![]() else
                    else
![]() {
                    {
![]() gen.Emit(OpCodes.Ldarg, index);
                        gen.Emit(OpCodes.Ldarg, index);
![]() }
                    }
![]() break;
                    break;
![]() }
            }
![]() }
        }
![]()
![]() public static T GetInterface<T>(Delegate GM)
        public static T GetInterface<T>(Delegate GM)
![]() {
        {
![]() if (typeof(T).IsInterface)
            if (typeof(T).IsInterface)
![]() {
            {
![]() Type delegateType = GM.GetType();
                Type delegateType = GM.GetType();
![]() if (delegateType.IsGenericType)
                if (delegateType.IsGenericType)
![]() {
                {
![]() if (typeof(MulticastDelegate).IsAssignableFrom(delegateType.GetGenericTypeDefinition()))
                    if (typeof(MulticastDelegate).IsAssignableFrom(delegateType.GetGenericTypeDefinition()))
![]() {
                    {
![]() Type[] genericTypes = delegateType.GetGenericArguments();
                        Type[] genericTypes = delegateType.GetGenericArguments();
![]() if (genericTypes.Length == 1)
                        if (genericTypes.Length == 1)
![]() {
                        {
![]() Type genericType = genericTypes[0];
                            Type genericType = genericTypes[0];
![]()
![]() #if SAVE
#if SAVE
![]() string theFilename = "InterfaceGenerator.Attachments.dll";
                            string theFilename = "InterfaceGenerator.Attachments.dll";
![]() #endif
#endif
![]() AssemblyName aname = new AssemblyName();
                            AssemblyName aname = new AssemblyName();
![]() aname.Name = string.Format("InterfaceGenerator.Attachments.{0}", GetRandomString(16));
                            aname.Name = string.Format("InterfaceGenerator.Attachments.{0}", GetRandomString(16));
![]() aname.Version = new Version("2.0.0.0");
                            aname.Version = new Version("2.0.0.0");
![]() AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(aname,
                            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(aname,
![]() #if SAVE
#if SAVE
![]() AssemblyBuilderAccess.RunAndSave
 AssemblyBuilderAccess.RunAndSave
![]() #else
#else
![]() AssemblyBuilderAccess.Run
 AssemblyBuilderAccess.Run
![]() #endif
#endif
![]() );
);
![]() ModuleBuilder module = assembly.DefineDynamicModule(GetRandomString(8)
                            ModuleBuilder module = assembly.DefineDynamicModule(GetRandomString(8)
![]() #if SAVE
#if SAVE
![]() , theFilename
, theFilename
![]() #endif
#endif
![]() );
);
![]() TypeBuilder builder = module.DefineType(GetRandomString(16), TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public);
                            TypeBuilder builder = module.DefineType(GetRandomString(16), TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public);
![]() builder.AddInterfaceImplementation(typeof(T));
                            builder.AddInterfaceImplementation(typeof(T));
![]()
![]() // 先定义成员域,用于保存传入的委托。
                            // 先定义成员域,用于保存传入的委托。
![]() FieldBuilder field = builder.DefineField(GetRandomString(8), delegateType, FieldAttributes.Private);
                            FieldBuilder field = builder.DefineField(GetRandomString(8), delegateType, FieldAttributes.Private);
![]()
![]() // 定义构造器。
                            // 定义构造器。
![]() ConstructorBuilder ctor = builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { delegateType });
                            ConstructorBuilder ctor = builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { delegateType });
![]() ILGenerator ctorGen = ctor.GetILGenerator();
                            ILGenerator ctorGen = ctor.GetILGenerator();
![]() ctorGen.Emit(OpCodes.Ldarg_0);
                            ctorGen.Emit(OpCodes.Ldarg_0);
![]() ctorGen.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[] { }));
                            ctorGen.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[] { }));
![]() ctorGen.Emit(OpCodes.Ldarg_0);
                            ctorGen.Emit(OpCodes.Ldarg_0);
![]() ctorGen.Emit(OpCodes.Ldarg_1);
                            ctorGen.Emit(OpCodes.Ldarg_1);
![]() ctorGen.Emit(OpCodes.Stfld, field);
                            ctorGen.Emit(OpCodes.Stfld, field);
![]() ctorGen.Emit(OpCodes.Ret);
                            ctorGen.Emit(OpCodes.Ret);
![]()
![]() // 虽然这么写,但事实上接口只有一个方法。
                            // 虽然这么写,但事实上接口只有一个方法。
![]() foreach (MethodInfo bmi in typeof(T).GetMethods())
                            foreach (MethodInfo bmi in typeof(T).GetMethods())
![]() {
                            {
![]() ParameterInfo[] paramInfos = bmi.GetParameters();
                                ParameterInfo[] paramInfos = bmi.GetParameters();
![]() Type[] argTypes = new Type[paramInfos.Length];
                                Type[] argTypes = new Type[paramInfos.Length];
![]() int i = 0;
                                int i = 0;
![]() foreach (ParameterInfo pi in paramInfos)
                                foreach (ParameterInfo pi in paramInfos)
![]() {
                                {
![]() argTypes[i++] = pi.ParameterType;
                                    argTypes[i++] = pi.ParameterType;
![]() }
                                }
![]() MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.Public;
                                MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.Public;
![]() MethodBuilder method = builder.DefineMethod(bmi.Name, attributes, bmi.ReturnType, argTypes);
                                MethodBuilder method = builder.DefineMethod(bmi.Name, attributes, bmi.ReturnType, argTypes);
![]() builder.DefineMethodOverride(method, bmi);
                                builder.DefineMethodOverride(method, bmi);
![]() MethodInfo dmi = delegateType.GetMethod("Invoke");
                                MethodInfo dmi = delegateType.GetMethod("Invoke");
![]() ILGenerator methodGen = method.GetILGenerator();
                                ILGenerator methodGen = method.GetILGenerator();
![]() bool hasReturn = false;
                                bool hasReturn = false;
![]() if (dmi.ReturnType != typeof(void))
                                if (dmi.ReturnType != typeof(void))
![]() {
                                {
![]() methodGen.DeclareLocal(dmi.ReturnType);
                                    methodGen.DeclareLocal(dmi.ReturnType);
![]() hasReturn = true;
                                    hasReturn = true;
![]() }
                                }
![]() methodGen.Emit(OpCodes.Ldarg_0);
                                methodGen.Emit(OpCodes.Ldarg_0);
![]() methodGen.Emit(OpCodes.Ldfld, field);
                                methodGen.Emit(OpCodes.Ldfld, field);
![]()
![]() i = 0;
                                i = 0;
![]() foreach (ParameterInfo pi in dmi.GetParameters())
                                foreach (ParameterInfo pi in dmi.GetParameters())
![]() {
                                {
![]() LoadArg(methodGen, i + 1);
                                    LoadArg(methodGen, i + 1);
![]() if (!pi.ParameterType.IsAssignableFrom(argTypes[i]))
                                    if (!pi.ParameterType.IsAssignableFrom(argTypes[i]))
![]() {
                                    {
![]() if (argTypes[i].IsClass)
                                        if (argTypes[i].IsClass)
![]() {
                                        {
![]() methodGen.Emit(OpCodes.Castclass, pi.ParameterType);
                                            methodGen.Emit(OpCodes.Castclass, pi.ParameterType);
![]() }
                                        }
![]() else
                                        else
![]() {
                                        {
![]() methodGen.Emit(OpCodes.Unbox, pi.ParameterType);
                                            methodGen.Emit(OpCodes.Unbox, pi.ParameterType);
![]() }
                                        }
![]() }
                                    }
![]() i++;
                                    i++;
![]() }
                                }
![]() methodGen.Emit(OpCodes.Callvirt, dmi);
                                methodGen.Emit(OpCodes.Callvirt, dmi);
![]() if (hasReturn)
                                if (hasReturn)
![]() {
                                {
![]() methodGen.Emit(OpCodes.Stloc_0);
                                    methodGen.Emit(OpCodes.Stloc_0);
![]() methodGen.Emit(OpCodes.Ldloc_0);
                                    methodGen.Emit(OpCodes.Ldloc_0);
![]() }
                                }
![]() methodGen.Emit(OpCodes.Ret);
                                methodGen.Emit(OpCodes.Ret);
![]() }
                            }
![]() Type target = builder.CreateType();
                            Type target = builder.CreateType();
![]() #if SAVE
#if SAVE
![]() assembly.Save(theFilename);
                            assembly.Save(theFilename);
![]() #endif
#endif
![]() ConstructorInfo ci = target.GetConstructor(new Type[] { delegateType });
                            ConstructorInfo ci = target.GetConstructor(new Type[] { delegateType });
![]() return (T) ci.Invoke(new object[] { GM });
                            return (T) ci.Invoke(new object[] { GM });
![]() }
                        }
![]() }
                    }
![]() }
                }
![]() }
            }
![]() return default(T);
            return default(T);
![]() }
        }
![]() }
    }
![]() }
}
![]() 
![]() using System;
using System;
![]() using System.Collections.Generic;
using System.Collections.Generic;
![]() using System.Reflection;
using System.Reflection;
![]() using System.Text;
using System.Text;
![]()
![]() namespace GenericMethodTest
namespace GenericMethodTest
![]() {
{
![]() // 为泛型方法定义的委托
    // 为泛型方法定义的委托
![]() public delegate void GM<T>(T obj, IList<T> list);
    public delegate void GM<T>(T obj, IList<T> list);
![]()
![]() // 为非泛型方法定义的接口
    // 为非泛型方法定义的接口
![]() public interface ING
    public interface ING
![]() {
    {
![]() void NGM(object obj, object list);
        void NGM(object obj, object list);
![]() }
    }
![]()
![]() class Program
    class Program
![]() {
    {
![]() static void Main(string[] args)
        static void Main(string[] args)
![]() {
        {
![]() List<int> list = new List<int>();
            List<int> list = new List<int>();
![]() System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
![]() watch.Reset();
            watch.Reset();
![]() watch.Start();
            watch.Start();
![]() for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++)
![]() {
            {
![]() list.Add(i);
                list.Add(i);
![]() }
            }
![]() watch.Stop();
            watch.Stop();
![]() long l1 = watch.ElapsedMilliseconds;
            long l1 = watch.ElapsedMilliseconds;
![]() watch.Reset();
            watch.Reset();
![]() watch.Start();
            watch.Start();
![]() GM<int> gm = new GM<int>(Program.Add);
            GM<int> gm = new GM<int>(Program.Add);
![]() for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++)
![]() {
            {
![]() gm(i, list);
                gm(i, list);
![]() }
            }
![]() watch.Stop();
            watch.Stop();
![]() long l2 = watch.ElapsedMilliseconds;
            long l2 = watch.ElapsedMilliseconds;
![]() watch.Reset();
            watch.Reset();
![]() watch.Start();
            watch.Start();
![]() MethodInfo mi = typeof(Program).GetMethod("Add");
            MethodInfo mi = typeof(Program).GetMethod("Add");
![]() MethodInfo gmi = mi.MakeGenericMethod(typeof(int));
            MethodInfo gmi = mi.MakeGenericMethod(typeof(int));
![]() for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++)
![]() {
            {
![]() gmi.Invoke(null, new object[] { i, list });
                gmi.Invoke(null, new object[] { i, list });
![]() }
            }
![]() watch.Stop();
            watch.Stop();
![]() long l3 = watch.ElapsedMilliseconds;
            long l3 = watch.ElapsedMilliseconds;
![]() watch.Reset();
            watch.Reset();
![]() watch.Start();
            watch.Start();
![]() ING ng1 = GetNGC(typeof(int), typeof(Program), "Add");
            ING ng1 = GetNGC(typeof(int), typeof(Program), "Add");
![]() for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++)
![]() {
            {
![]() ng1.NGM(i, list);
                ng1.NGM(i, list);
![]() }
            }
![]() watch.Stop();
            watch.Stop();
![]() long l4 = watch.ElapsedMilliseconds;
            long l4 = watch.ElapsedMilliseconds;
![]() watch.Reset();
            watch.Reset();
![]() watch.Start();
            watch.Start();
![]() ING ng2 = InterfaceGenerator.GetInterface<ING>(new GM<int>(Program.Add));
            ING ng2 = InterfaceGenerator.GetInterface<ING>(new GM<int>(Program.Add));
![]() for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++)
![]() {
            {
![]() ng2.NGM(i, list);
                ng2.NGM(i, list);
![]() }
            }
![]() watch.Stop();
            watch.Stop();
![]() long l5 = watch.ElapsedMilliseconds;
            long l5 = watch.ElapsedMilliseconds;
![]() Console.WriteLine("{0}\n{1} vs {2} vs {3} vs {4} vs {5}", list.Count, l1, l2, l3, l4, l5);
            Console.WriteLine("{0}\n{1} vs {2} vs {3} vs {4} vs {5}", list.Count, l1, l2, l3, l4, l5);
![]() Console.ReadLine();
            Console.ReadLine();
![]() }
        }
![]()
![]() public static void Add<T>(T obj, IList<T> list)
        public static void Add<T>(T obj, IList<T> list)
![]() {
        {
![]() list.Add(obj);
            list.Add(obj);
![]() }
        }
![]()
![]() static ING GetNGC(Type genericType, Type methodType, string methodName)
        static ING GetNGC(Type genericType, Type methodType, string methodName)
![]() {
        {
![]() MethodInfo mi = methodType.GetMethod(methodName);
            MethodInfo mi = methodType.GetMethod(methodName);
![]() MethodInfo gmi = mi.MakeGenericMethod(genericType);
            MethodInfo gmi = mi.MakeGenericMethod(genericType);
![]() Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
            Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
![]() return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
            return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
![]() }
        }
![]() }
    }
![]()
![]() public class GClass<T> : ING
    public class GClass<T> : ING
![]() {
    {
![]() private GM<T> m_gmd;
        private GM<T> m_gmd;
![]()
![]() public GClass(GM<T> gmd)
        public GClass(GM<T> gmd)
![]() {
        {
![]() m_gmd = gmd;
            m_gmd = gmd;
![]() }
        }
![]()
![]() INGClass 成员
        INGClass 成员
![]() }
    }
![]() }
}
![]() 
假定有这样一个方法:
 public static void Add<T>(T obj, IList<T> list)
public static void Add<T>(T obj, IList<T> list) {
{ list.Add(obj);
      list.Add(obj); }
}
 Add(Type type, object obj, object list);
Add(Type type, object obj, object list); void Add(Type type, object obj, object list)
void Add(Type type, object obj, object list) {
{ MethodInfo mi = typeof(MyType).GetMethod("Add");
    MethodInfo mi = typeof(MyType).GetMethod("Add"); MethodInfo gmi = mi.MakeGenericMethod(type);
    MethodInfo gmi = mi.MakeGenericMethod(type); gmi.Invoke(new object[] { obj, list });
    gmi.Invoke(new object[] { obj, list }); }
}先定义一个泛型包装委托:
 public delegate void GM<T>(T obj, IList<T> list);
public delegate void GM<T>(T obj, IList<T> list); interface ING
interface ING {
{ void NGM(object obj, object list);
    void NGM(object obj, object list); }
} public class GClass<T> : ING
public class GClass<T> : ING {
{ private GM<T> m_gmd;
    private GM<T> m_gmd;
 public GClass(GM<T> gmd)
    public GClass(GM<T> gmd) {
    { m_gmd = gmd;
        m_gmd = gmd; }
    }
 #region INGClass 成员
    #region INGClass 成员
 public void NGM(object obj, object list)
    public void NGM(object obj, object list) {
    { m_gmd((T)obj, (IList<T>)list);
        m_gmd((T)obj, (IList<T>)list); }
    }
 #endregion
    #endregion }
} static ING GetNGC(Type genericType, Type methodType, string methodName)
static ING GetNGC(Type genericType, Type methodType, string methodName) {
{ MethodInfo mi = methodType.GetMethod(methodName);
    MethodInfo mi = methodType.GetMethod(methodName); MethodInfo gmi = mi.MakeGenericMethod(genericType);
    MethodInfo gmi = mi.MakeGenericMethod(genericType); Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
    Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi); return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
    return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING; }
}
 ING ng = GetNGC(typeof(int), typeof(MyType), "Add");
ING ng = GetNGC(typeof(int), typeof(MyType), "Add"); ng.NGM(i, list);
ng.NGM(i, list);- 定义泛型委托;
- 定义非泛型接口;
- 实现这个接口;
- 通过泛型委托获取非泛型接口的实现。
 using System;
using System; using System.Collections.Generic;
using System.Collections.Generic; using System.Reflection;
using System.Reflection; using System.Reflection.Emit;
using System.Reflection.Emit; using System.Text;
using System.Text;
 namespace GenericMethodTest
namespace GenericMethodTest {
{ /// <summary>
    /// <summary> /// 接口生成器
    /// 接口生成器 /// </summary>
    /// </summary> internal static class InterfaceGenerator
    internal static class InterfaceGenerator {
    { private static Random _Random = new Random();
        private static Random _Random = new Random();
 private static char GetRandomLetter()
        private static char GetRandomLetter() {
        { int i = (_Random.Next() % 26) + 97;
            int i = (_Random.Next() % 26) + 97; byte[] b = BitConverter.GetBytes(i);
            byte[] b = BitConverter.GetBytes(i); return BitConverter.ToChar(b, 0);
            return BitConverter.ToChar(b, 0); }
        }
 private static string GetRandomString(int n)
        private static string GetRandomString(int n) {
        { char[] chars = new char[n];
            char[] chars = new char[n]; for (int i = 0; i < n; i++)
            for (int i = 0; i < n; i++) {
            { chars[i] = GetRandomLetter();
                chars[i] = GetRandomLetter(); }
            } return new string(chars);
            return new string(chars); }
        }
 private static void LoadArg(ILGenerator gen, int index)
        private static void LoadArg(ILGenerator gen, int index) {
        { switch (index)
            switch (index) {
            { case 0:
                case 0: gen.Emit(OpCodes.Ldarg_0);
                    gen.Emit(OpCodes.Ldarg_0); break;
                    break; case 1:
                case 1: gen.Emit(OpCodes.Ldarg_1);
                    gen.Emit(OpCodes.Ldarg_1); break;
                    break; case 2:
                case 2: gen.Emit(OpCodes.Ldarg_2);
                    gen.Emit(OpCodes.Ldarg_2); break;
                    break; case 3:
                case 3: gen.Emit(OpCodes.Ldarg_3);
                    gen.Emit(OpCodes.Ldarg_3); break;
                    break; default:
                default: if (index < 128)
                    if (index < 128) {
                    { gen.Emit(OpCodes.Ldarg_S, index);
                        gen.Emit(OpCodes.Ldarg_S, index); }
                    } else
                    else {
                    { gen.Emit(OpCodes.Ldarg, index);
                        gen.Emit(OpCodes.Ldarg, index); }
                    } break;
                    break; }
            } }
        }
 public static T GetInterface<T>(Delegate GM)
        public static T GetInterface<T>(Delegate GM) {
        { if (typeof(T).IsInterface)
            if (typeof(T).IsInterface) {
            { Type delegateType = GM.GetType();
                Type delegateType = GM.GetType(); if (delegateType.IsGenericType)
                if (delegateType.IsGenericType) {
                { if (typeof(MulticastDelegate).IsAssignableFrom(delegateType.GetGenericTypeDefinition()))
                    if (typeof(MulticastDelegate).IsAssignableFrom(delegateType.GetGenericTypeDefinition())) {
                    { Type[] genericTypes = delegateType.GetGenericArguments();
                        Type[] genericTypes = delegateType.GetGenericArguments(); if (genericTypes.Length == 1)
                        if (genericTypes.Length == 1) {
                        { Type genericType = genericTypes[0];
                            Type genericType = genericTypes[0];
 #if SAVE
#if SAVE string theFilename = "InterfaceGenerator.Attachments.dll";
                            string theFilename = "InterfaceGenerator.Attachments.dll"; #endif
#endif AssemblyName aname = new AssemblyName();
                            AssemblyName aname = new AssemblyName(); aname.Name = string.Format("InterfaceGenerator.Attachments.{0}", GetRandomString(16));
                            aname.Name = string.Format("InterfaceGenerator.Attachments.{0}", GetRandomString(16)); aname.Version = new Version("2.0.0.0");
                            aname.Version = new Version("2.0.0.0"); AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(aname,
                            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(aname, #if SAVE
#if SAVE AssemblyBuilderAccess.RunAndSave
 AssemblyBuilderAccess.RunAndSave #else
#else AssemblyBuilderAccess.Run
 AssemblyBuilderAccess.Run #endif
#endif );
); ModuleBuilder module = assembly.DefineDynamicModule(GetRandomString(8)
                            ModuleBuilder module = assembly.DefineDynamicModule(GetRandomString(8) #if SAVE
#if SAVE , theFilename
, theFilename #endif
#endif );
); TypeBuilder builder = module.DefineType(GetRandomString(16), TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public);
                            TypeBuilder builder = module.DefineType(GetRandomString(16), TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public); builder.AddInterfaceImplementation(typeof(T));
                            builder.AddInterfaceImplementation(typeof(T));
 // 先定义成员域,用于保存传入的委托。
                            // 先定义成员域,用于保存传入的委托。 FieldBuilder field = builder.DefineField(GetRandomString(8), delegateType, FieldAttributes.Private);
                            FieldBuilder field = builder.DefineField(GetRandomString(8), delegateType, FieldAttributes.Private);
 // 定义构造器。
                            // 定义构造器。 ConstructorBuilder ctor = builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { delegateType });
                            ConstructorBuilder ctor = builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { delegateType }); ILGenerator ctorGen = ctor.GetILGenerator();
                            ILGenerator ctorGen = ctor.GetILGenerator(); ctorGen.Emit(OpCodes.Ldarg_0);
                            ctorGen.Emit(OpCodes.Ldarg_0); ctorGen.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[] { }));
                            ctorGen.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[] { })); ctorGen.Emit(OpCodes.Ldarg_0);
                            ctorGen.Emit(OpCodes.Ldarg_0); ctorGen.Emit(OpCodes.Ldarg_1);
                            ctorGen.Emit(OpCodes.Ldarg_1); ctorGen.Emit(OpCodes.Stfld, field);
                            ctorGen.Emit(OpCodes.Stfld, field); ctorGen.Emit(OpCodes.Ret);
                            ctorGen.Emit(OpCodes.Ret);
 // 虽然这么写,但事实上接口只有一个方法。
                            // 虽然这么写,但事实上接口只有一个方法。 foreach (MethodInfo bmi in typeof(T).GetMethods())
                            foreach (MethodInfo bmi in typeof(T).GetMethods()) {
                            { ParameterInfo[] paramInfos = bmi.GetParameters();
                                ParameterInfo[] paramInfos = bmi.GetParameters(); Type[] argTypes = new Type[paramInfos.Length];
                                Type[] argTypes = new Type[paramInfos.Length]; int i = 0;
                                int i = 0; foreach (ParameterInfo pi in paramInfos)
                                foreach (ParameterInfo pi in paramInfos) {
                                { argTypes[i++] = pi.ParameterType;
                                    argTypes[i++] = pi.ParameterType; }
                                } MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.Public;
                                MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.Public; MethodBuilder method = builder.DefineMethod(bmi.Name, attributes, bmi.ReturnType, argTypes);
                                MethodBuilder method = builder.DefineMethod(bmi.Name, attributes, bmi.ReturnType, argTypes); builder.DefineMethodOverride(method, bmi);
                                builder.DefineMethodOverride(method, bmi); MethodInfo dmi = delegateType.GetMethod("Invoke");
                                MethodInfo dmi = delegateType.GetMethod("Invoke"); ILGenerator methodGen = method.GetILGenerator();
                                ILGenerator methodGen = method.GetILGenerator(); bool hasReturn = false;
                                bool hasReturn = false; if (dmi.ReturnType != typeof(void))
                                if (dmi.ReturnType != typeof(void)) {
                                { methodGen.DeclareLocal(dmi.ReturnType);
                                    methodGen.DeclareLocal(dmi.ReturnType); hasReturn = true;
                                    hasReturn = true; }
                                } methodGen.Emit(OpCodes.Ldarg_0);
                                methodGen.Emit(OpCodes.Ldarg_0); methodGen.Emit(OpCodes.Ldfld, field);
                                methodGen.Emit(OpCodes.Ldfld, field);
 i = 0;
                                i = 0; foreach (ParameterInfo pi in dmi.GetParameters())
                                foreach (ParameterInfo pi in dmi.GetParameters()) {
                                { LoadArg(methodGen, i + 1);
                                    LoadArg(methodGen, i + 1); if (!pi.ParameterType.IsAssignableFrom(argTypes[i]))
                                    if (!pi.ParameterType.IsAssignableFrom(argTypes[i])) {
                                    { if (argTypes[i].IsClass)
                                        if (argTypes[i].IsClass) {
                                        { methodGen.Emit(OpCodes.Castclass, pi.ParameterType);
                                            methodGen.Emit(OpCodes.Castclass, pi.ParameterType); }
                                        } else
                                        else {
                                        { methodGen.Emit(OpCodes.Unbox, pi.ParameterType);
                                            methodGen.Emit(OpCodes.Unbox, pi.ParameterType); }
                                        } }
                                    } i++;
                                    i++; }
                                } methodGen.Emit(OpCodes.Callvirt, dmi);
                                methodGen.Emit(OpCodes.Callvirt, dmi); if (hasReturn)
                                if (hasReturn) {
                                { methodGen.Emit(OpCodes.Stloc_0);
                                    methodGen.Emit(OpCodes.Stloc_0); methodGen.Emit(OpCodes.Ldloc_0);
                                    methodGen.Emit(OpCodes.Ldloc_0); }
                                } methodGen.Emit(OpCodes.Ret);
                                methodGen.Emit(OpCodes.Ret); }
                            } Type target = builder.CreateType();
                            Type target = builder.CreateType(); #if SAVE
#if SAVE assembly.Save(theFilename);
                            assembly.Save(theFilename); #endif
#endif ConstructorInfo ci = target.GetConstructor(new Type[] { delegateType });
                            ConstructorInfo ci = target.GetConstructor(new Type[] { delegateType }); return (T) ci.Invoke(new object[] { GM });
                            return (T) ci.Invoke(new object[] { GM }); }
                        } }
                    } }
                } }
            } return default(T);
            return default(T); }
        } }
    } }
}
结论:
以下是测试代码:
 using System;
using System; using System.Collections.Generic;
using System.Collections.Generic; using System.Reflection;
using System.Reflection; using System.Text;
using System.Text;
 namespace GenericMethodTest
namespace GenericMethodTest {
{ // 为泛型方法定义的委托
    // 为泛型方法定义的委托 public delegate void GM<T>(T obj, IList<T> list);
    public delegate void GM<T>(T obj, IList<T> list);
 // 为非泛型方法定义的接口
    // 为非泛型方法定义的接口 public interface ING
    public interface ING {
    { void NGM(object obj, object list);
        void NGM(object obj, object list); }
    }
 class Program
    class Program {
    { static void Main(string[] args)
        static void Main(string[] args) {
        { List<int> list = new List<int>();
            List<int> list = new List<int>(); System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Reset();
            watch.Reset(); watch.Start();
            watch.Start(); for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++) {
            { list.Add(i);
                list.Add(i); }
            } watch.Stop();
            watch.Stop(); long l1 = watch.ElapsedMilliseconds;
            long l1 = watch.ElapsedMilliseconds; watch.Reset();
            watch.Reset(); watch.Start();
            watch.Start(); GM<int> gm = new GM<int>(Program.Add);
            GM<int> gm = new GM<int>(Program.Add); for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++) {
            { gm(i, list);
                gm(i, list); }
            } watch.Stop();
            watch.Stop(); long l2 = watch.ElapsedMilliseconds;
            long l2 = watch.ElapsedMilliseconds; watch.Reset();
            watch.Reset(); watch.Start();
            watch.Start(); MethodInfo mi = typeof(Program).GetMethod("Add");
            MethodInfo mi = typeof(Program).GetMethod("Add"); MethodInfo gmi = mi.MakeGenericMethod(typeof(int));
            MethodInfo gmi = mi.MakeGenericMethod(typeof(int)); for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++) {
            { gmi.Invoke(null, new object[] { i, list });
                gmi.Invoke(null, new object[] { i, list }); }
            } watch.Stop();
            watch.Stop(); long l3 = watch.ElapsedMilliseconds;
            long l3 = watch.ElapsedMilliseconds; watch.Reset();
            watch.Reset(); watch.Start();
            watch.Start(); ING ng1 = GetNGC(typeof(int), typeof(Program), "Add");
            ING ng1 = GetNGC(typeof(int), typeof(Program), "Add"); for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++) {
            { ng1.NGM(i, list);
                ng1.NGM(i, list); }
            } watch.Stop();
            watch.Stop(); long l4 = watch.ElapsedMilliseconds;
            long l4 = watch.ElapsedMilliseconds; watch.Reset();
            watch.Reset(); watch.Start();
            watch.Start(); ING ng2 = InterfaceGenerator.GetInterface<ING>(new GM<int>(Program.Add));
            ING ng2 = InterfaceGenerator.GetInterface<ING>(new GM<int>(Program.Add)); for (int i = 0; i < 1000000; i++)
            for (int i = 0; i < 1000000; i++) {
            { ng2.NGM(i, list);
                ng2.NGM(i, list); }
            } watch.Stop();
            watch.Stop(); long l5 = watch.ElapsedMilliseconds;
            long l5 = watch.ElapsedMilliseconds; Console.WriteLine("{0}\n{1} vs {2} vs {3} vs {4} vs {5}", list.Count, l1, l2, l3, l4, l5);
            Console.WriteLine("{0}\n{1} vs {2} vs {3} vs {4} vs {5}", list.Count, l1, l2, l3, l4, l5); Console.ReadLine();
            Console.ReadLine(); }
        }
 public static void Add<T>(T obj, IList<T> list)
        public static void Add<T>(T obj, IList<T> list) {
        { list.Add(obj);
            list.Add(obj); }
        }
 static ING GetNGC(Type genericType, Type methodType, string methodName)
        static ING GetNGC(Type genericType, Type methodType, string methodName) {
        { MethodInfo mi = methodType.GetMethod(methodName);
            MethodInfo mi = methodType.GetMethod(methodName); MethodInfo gmi = mi.MakeGenericMethod(genericType);
            MethodInfo gmi = mi.MakeGenericMethod(genericType); Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi);
            Delegate gmd = Delegate.CreateDelegate(typeof(GM<>).MakeGenericType(genericType), gmi); return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING;
            return Activator.CreateInstance(typeof(GClass<>).MakeGenericType(genericType), gmd) as ING; }
        } }
    }
 public class GClass<T> : ING
    public class GClass<T> : ING {
    { private GM<T> m_gmd;
        private GM<T> m_gmd;
 public GClass(GM<T> gmd)
        public GClass(GM<T> gmd) {
        { m_gmd = gmd;
            m_gmd = gmd; }
        }
 INGClass 成员
        INGClass 成员 }
    } }
}
测试结果:
| 方案 | 耗时 | 比对 | 其他优点 | 
| 直接调用 | 18 | 1 | 不通用 | 
| 泛型委托包装 | 43 | 2.39 | 不通用 | 
| 反射 | 16538 | 918.78 | 通用,不需额外定义 | 
| 非泛型接口包装 | 60 | 3.33 | 通用,需要额外定义并实现 | 
| 动态生成的非泛型接口包装 | 72 | 4 | 通用,需要额外定义 | 
 
                    
                     
                    
                 
                    
                

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号