簡體   English   中英

c#測試一個對象是否實現了ISurface <T> 任何類型使用.GetType()。GetInterface(typeof(ISurface &lt;&gt;)。FullName)

[英]c# testing if an object implements ISurface<T> of any Type using .GetType().GetInterface(typeof(ISurface<>).FullName)

我有一個插件架構,我需要檢測所有實現任何類型的接口ISurface<T>的插件(即測試ISurface<> )。 我看到這里有幾個建議使用LINQ(例如這個 ),我想知道是否有理由支持這個:

.GetType().GetInterface("ISurface`1")

編輯 :關於硬編碼接口名稱,我假設如果名稱是從實際接口直接提取的話,這些問題將得到緩解,如下面提到的Tim:

.GetType().GetInterface(typeof(ISurface<>).FullName)

使用 .FullName ,名稱空間歧義也應該沒有問題。 除了硬編碼,我主要對方法本身感興趣,因為它看起來比通過一系列類型屬性檢查/ LINQ語法更簡潔。 然后,我不知道引擎蓋下發生了什么。

以下是如何提取ISurface<anything>類型的所有受支持接口:

void Main()
{
    var supportedInterfaces =
        from intf in typeof(Test).GetInterfaces()
        where intf.IsGenericType
        let genericIntf = intf.GetGenericTypeDefinition()
        where genericIntf == typeof(ISurface<>)
        select intf;

    supportedInterfaces.Dump();
}

public class Test : ISurface<int>
{
}

public interface ISurface<T>
{
}

您可以在LINQPad中測試它( .Dump()擴展方法是LINQPad擴展)。

如果只檢查接口的“簡單”名稱(而不是完全指定的類名,包括名稱空間),那么如果在另一個名稱空間中有另一個具有相同名稱的接口,則會遇到問題。

如果使用完全指定的類名調用GetInterface方法,它應該可以正常工作。

MSDN特別提到對於泛型類型,你應該指定受損的名稱,所以我希望它能正常工作。

當然,如果是最好的方法,可以辯論。 如果更改接口名稱,則會出現問題。

那么,這是一個可能會發生變化的實施細節 另外,你安全地失去了運行時類型。 我寧願堅持使用公共方法 - 要么使用Linq,要么使用反射。

有幾個原因可以解釋為什么你可能不想這樣做:

  1. 如果重構代碼以使"ISurface`1"不再有效(例如添加或刪除類型參數或重命名接口),編譯器將無法捕獲它。 這可以通過將其替換為typeof(ISurface<>).Name來解決typeof(ISurface<>).Name
  2. 如果在另一個命名空間中存在ISurface<> ,則它是不明確的(或者,至少,乍一看它似乎是這樣)。

我可能會使用您鏈接的解決方案 ,可能包含在擴展方法中,以便我可以更簡單地調用它,例如

public static Type GetInterface(this Type type, Type targetType)
{
    return type.GetInterfaces().SingleOrDefault(t => t.IsGenericType
                          && t.GetGenericTypeDefinition() == targetType);
}
public class Surface : ISurface<int> { /* ... */ }

typeof(Surface).GetInterface(typeof(ISurface<>)); //returns typeof(ISurface<int>)
typeof(NotASurface).GetInterface(typeof(ISurface<>)); //returns null

如果您對相關接口有任何控制權,我建議ISurface<T>應該從非通用ISurface繼承。 該類型又可以包括可以以各種方式指示ISurface<T>可用的類型的成員(例如,如果定義了接口ITypeRegistrar { Register<TType>(info about type);} ,非泛型ISurface可以包含RegisterSupportedTypes(ITypeRegistrar registrar)方法。根據與每種類型相關的確切信息,典型的實現可能如下所示:

void RegisterSupportedTypes(ITypeRegistrar registrar)
{
   registrar.Register<Circle>(circleFactory);
   registrar.Register<Square>(squareFactory);
   registrar.Register<Rhombus>(rhombusFactory);
}

客戶端代碼將接收每個項目作為其實際泛型類型,因此使用此方法將允許程序在沒有類型轉換或反射的情況下運行。 因為.NET沒有開放泛型委托的概念,所以客戶端代碼必須手動實現ITypeRegistrar接口(而不是使用lambda語法之類的東西作為創建委托的快捷方式),但實現的方法可以做類似存儲引用的操作將提供的工廠放入靜態泛型類的字段而不使用Reflection,這是委托無法做到的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM