在使用dapper时,都用IConnection上有一个Query<T>的函数。咱们项目组的成员提出了一个问题:我不知道怎么去调用它?
为了demo这个情形,我打算在string类上写个扩展方法。这个方法假设叫作IsOK。
咱们先分解一下需求:程序员
IsOK<T>(T b)
和他的一个重载IsOK<T1,T2>(T1 a, T2 b)
IsOK<T1,T2>(T1 a, T2 b)
函数T1, T2要可以动态的变换类型。例如我能够传入参数 int, byte,就会调用 IsOK<int, byte>(int a, byte b)
,下面会详解这个需求。
c#
public static class StringExtension { public static bool IsOK(this string a, string b) { return a.StartsWith(b[0].ToString()); } public static bool IsOK<T>(this string a, T b) { return a.StartsWith(b.ToString()); } public static bool IsOK<T1, T2>(this string a, T1 b, T2 c) { return a.StartsWith(b.ToString()); } }
这里有一点值得说的是,反射泛型须要用到你的那个Extionsion类。也就是说,咱们对string类进行扩展了,可是咱们在反射的时候,并不能使用string类,应该使用咱们本身写的StringExtension类。
而后,咱们这里如何来判断是哪一个重载呢?在这里,由于个人参数个数不同IsOK<T1, T2>(this string a, T1 b, T2 c)
,我能够简单的判断参数的个数若是是3个,就是我想要的结果,注意IsOK<T1, T2>(this string a, T1 b, T2 c)
的参数是3个哦!
千万不要认为调用时,好像只提供了2个参数。其实这里是3个。
那么
var mi = typeof(StringExtension).GetMethods().FirstOrDefault(m => m.IsGenericMethod && m.Name == "IsOK" && m.GetParameters().Length == 3);
这样的一句代码,就能帮我找到我想要的泛型。
余下的,我只须要MakeGenericMethod
就能完成调用前的准备工做。服务器
我设想这样一个场景,若是我有这样一个函数app
static void Foo(string typename1, string typename2) { // TODO: need implement generic types. }
我但愿我能够这样调用:
Foo("int","float")
这样就能够调用到 string.IsOK(int a, float b)
。同理:
Foo("double","string")
=> string.IsOK(double a, string b)
Foo("MyClass1","MyClass2)
=> string.IsOK(MyClass1 a, MyClass2 b)
为何要这样作呢?
你再设想一下这个场景,若是程序是客户端+服务器端的程序,在客户端那边想调用string.IsOK<string, IntPtr>(string a, IntPtr b)
和string.IsOK<double, double>(double a, double b)
,那你应该怎么样作呢?是否是动态的反射要方便一点?咱们只须要把字符串的"string"转换成string类型,把"dobule"转换成double就好了。函数
static Tuple<object, object> Foo(string typename1, string typename2) { var p1 = Activator.CreateInstance(Type.GetType(typename1)); var p2 = Activator.CreateInstance(Type.GetType(typename2)); return new Tuple<object, object>(p1, p2); }
大的问题应该已经解决。this
在程序里面,咱们能够经过改变sp1和sp2的类型来调用这个泛型。code
class Program { static void Main(string[] args) { var mi = typeof(StringExtension).GetMethods().FirstOrDefault(m => m.IsGenericMethod && m.Name == "IsOK" && m.GetParameters().Length == 3); var h = "hello world"; var sp1 = "System.Int32"; var sp2 = "System.Double"; var t = Foo(sp1, sp2); var mi2 = mi.MakeGenericMethod(Type.GetType(sp1), Type.GetType(sp2)); mi2.Invoke(null, new object[] { h, t.Item1, t.Item2 }); // h.IsOK(p1, p2); Console.Read(); } static Tuple<object, object> Foo(string typename1, string typename2) { var p1 = Activator.CreateInstance(Type.GetType(typename1)); var p2 = Activator.CreateInstance(Type.GetType(typename2)); return new Tuple<object, object>(p1, p2); } } public static class StringExtension { public static bool IsOK(this string a, string b) { return a.StartsWith(b[0].ToString()); } public static bool IsOK<T>(this string a, T b) { return a.StartsWith(b.ToString()); } public static bool IsOK<T1, T2>(this string a, T1 b, T2 c) { return a.StartsWith(b.ToString()); } }