2017年7月28日

呼叫泛型方法時Type為變數值

之前做過一次,呼叫泛型方法,但型態在寫的時候還沒決定,
或是這個型態是個變數,還未知的,要做成下面這樣

public GenericMethod(object obj);

Type type = someobject.GetType();
GenericMethod(someobject);
想當然程式寫成這個樣子是不可行的。
所以才寫這個筆記…



public class Checker
{
    public T Check(T data)
    {
        // ...........
    }
}
假設有個泛型方法長這樣。

第一次寫的時候用的是System.CodeDom.compiler這個命名空間的東西,
也就是把程式碼當成寫成字串,在執行時期再編譯,
這樣在寫那個字串的時候我就可以程式執行的時候再代入Check,Check,Check等等…
然後執行時編譯成dll,後面程式再動態呼叫dll,再呼叫這個函式。
聽起來就是很麻煩,程式也不好維護…

今天又再一次需要這樣做這樣的東西,
這次有看到好很多的方法,用System.Reflection

Type       type    = someThing.GetType();
MethodInfo method  = typeof(Checker).GetMethod("Check");
var        checker = new Checker();
var        retData = method.MakeGenericMethod(type).Invoke(checker, new object[]{ something });

這樣做就可以了,如果這個是static function,Invoke的第一個參數就不用帶實體進去,用null就可以,這裡比較麻煩的地方有兩點
  1. 回傳值都會是object,但是是可以成功轉型的,用is運算子來判斷也會是對的。
  2. 如果這個方法是有同名異式的(overwrite),用GetMethod就會出錯(找到不只一個),必須用GetMethods再去下條件做篩選。

Person someone = new Person();
var    checker = new Checker();

// 基本大家都知道的方法…
var newPerson = checker.check(someone);

// 新的做法
var type = someone.GetType();
var retData = typeof(Checker).GetMethod("Check").
                  MakeGenericMethod(type).
                  Invoke(checker, new object[]{ someone });
var newPerson = retData as Person;



沒有留言: