在使用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()); } }