通过泛型方法定义具有特定类型意义的方法是常用的手段。但在某些特定情况下,例如在一些通用的框架中,直到运行时才能确定泛型类型参数,就必须通过非泛型方式来调用泛型方法。
假定有这样一个方法:
public static void Add<T>(T obj, IList<T> list)
如果想换成这样调用:
Add(Type type, object obj, object list);
通常的方法是这样的:
void Add(Type type, object obj, object list)
}
当然,除了性能上的问题,这个方案是完全可行的。但是经过测试,通过这种包装后的耗时比直接的泛型调用相差将近1000倍。因此还需要一些折中一点的方案。为此,我请教了装配脑袋。他给出了一个非常好的方案:
先定义一个泛型包装委托:
public delegate void GM<T>(T obj, IList<T> list);
然后再定义一个非泛型包装的接口:
interface ING
}
然后再实现这个接口,在实现类中直接调用传入的泛型委托:
public class GClass<T> : ING
}
然后就可以非常简单地使用已有的泛型方法来获得一个非泛型接口实现了:
static ING GetNGC(Type genericType, Type methodType, string methodName)
通过执行所返回接口的非泛型方法来达到调用泛型方法的目的:
ING ng = GetNGC(typeof(int), typeof(MyType), "Add");
ng.NGM(i, list);
比对一下,耗时大约是直接泛型调用耗时的三倍。显然这个方案是一个非常实用的方案。归纳一下,一共需要四步:
- 定义泛型委托;
- 定义非泛型接口;
- 实现这个接口;
- 通过泛型委托获取非泛型接口的实现。
其中前两步比较简单,后两部稍嫌麻烦。于是,我们再进一步实现一个通用的接口实现及其输出。
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace GenericMethodTest
结论:
以下是测试代码:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace GenericMethodTest
测试结果:
| 方案 |
耗时 |
比对 |
其他优点 |
| 直接调用 |
18 |
1 |
不通用 |
| 泛型委托包装 |
43 |
2.39 |
不通用 |
| 反射 |
16538 |
918.78 |
通用,不需额外定义 |
| 非泛型接口包装 |
60 |
3.33 |
通用,需要额外定义并实现 |
| 动态生成的非泛型接口包装 |
72 |
4 |
通用,需要额外定义 |
相关文章: