Type類方法的使用-判斷某個類是否是某個介面的派生類
近期系統架構為以後資料整合做了一次調整,在更新完系統架構,調整Examples專案的時候發現,原系統框架中對於DTO型別的判斷使用的是字串進行比較,以前的寫法如下:
typeDTO.BaseType.FullName.Contains("DTOBase")
先說一下這一段程式碼的問題,typeDTO是傳入的DTO型別,判斷時使用的是其父類的型別的全類名,是否包含DTOBase,如果專案中直接繼承框架中的DTOBase,這段程式碼可以正常判斷,如果專案中在DTOBase的基礎上再加一層封裝,那這段程式碼就無法正確判斷typeDTO是否是DTOBase的派生類了。
另外,本次系統架構調整實體和聚合根的DTO分別繼承DTOEntityBase和DTOAggregateRootBase,但他們都實現了IDTO的泛型介面。我的想法是直接判斷傳入的DTO是否派生自IDTO,但由於IDTO是泛型介面,我不知道該如何判斷。
問過楊總之後,楊總給我講了一下泛型類的全名格式是這樣的“IDTO~1”,~1表示包含一個泛型引數。如果使用IDTO~1來判斷的話可以解決泛型介面判斷的問題,但還是存在我上面描述的二次封裝的問題。楊總又建議我們使用Type.MakeGenericType 方法,在執行時通過反射構造泛型型別的例項。程式碼如下:
Type _typeEntity = _typeDTO.BaseType.GenericTypeArguments[0];
Type genericSourceType = typeof(IDTO<>).MakeGenericType(new[] { _typeEntity });
在這裡詳細說明一下,第一行程式碼是獲取泛型引數的例項型別。用於第二行構造泛型型別。構造完成之後,我們就可以使用Type.IsAssignableFrom 方法判斷了。程式碼如下:
if (!genericSourceType.IsAssignableFrom(typeDTO))
{
throw new ArgumentException("不是有效的資料傳輸物件!", "typeDTO");
}
看到這的時候大家可能想到了Type.IsSubclassOf 方法,Type.IsSubclassOf 方法和Type.IsSubclassOf 方法的區別在於,前者只能用於判斷類的繼承關係。
舉個例子,看一下這兩種方法對於類繼承及介面實現的判斷,介面及其實現類及其實現類的子類定義如下:
interface I { // TODO }
class A : I { // TODO }
class B : A { // TODO }
IsSubclassOf和IsAssignableFrom的返回值為:
typeof(A).isAssignableFrom(typeof(I)); // false
typeof(A).isSubClassOf(typeof(I)); // false
typeof(I).isAssignableFrom(typeof(A)); // true
typeof(I).isAssignableFrom(typeof(B)); // true
typeof(B).isSubClassOf(typeof(I)); // false
typeof(A).isAssignableFrom(typeof(A)); // true
typeof(A).isSubClassof(typeof(A)); // false
typeof(A).isAssignableFrom(typeof(B)); // true
typeof(A).isSubClassof(typeof(B)); // false
typeof(B).isAssignableFrom(typeof(A)); // false
typeof(B).isSubClassof(typeof(A)); // true