簡體   English   中英

參數約束-調用檢查約束類型的方法嗎?

[英]Parameter constraints - call method to check type in constraint?

我有一個帶有通用參數的方法:

internal void DoSomething<T>(T workWithThis)
{
}

我現在想限制此方法,使其僅接受繼承我要指定的幾個接口之一的參數。 但是我還沒有找到解決方法。 我想要的是這樣的:

internal void DoSomething<T>(T workWithThis) where T : ISomething | ISomethingElse
{
}

顯然,這是行不通的,因此我嘗試使用靜態方法來檢查T的類型:

public static bool CheckType(Type t)
{
return */check here*/
}

internal void DoSomething<T>(T workWithThis) where T : CheckType(typeof(T))
{
}

顯然,這也不起作用。 問題是為什么? 根據我的理解,為什么編譯器會阻止我執行此操作,所以沒有理由不執行它

根據我的理解,為什么編譯器會阻止我執行此操作,所以沒有理由不執行它

編譯器阻止您執行此操作,因為您正在嘗試執行C#不支持的語言。 您嘗試使用的語法不符合C#規范第10.1.5節中的規定。

C#作為一種語言根本不支持您所需的方案。

現在, 為什么該語言不允許這種靈活性-歸結為以下常規平衡行為:

  • 有多少開發者將從中受益以及有多少
  • 其他開發人員難以理解更復雜的語言
  • 設計,實施和測試語言功能所需的資源(主要在Microsoft內部)

哦,這當然不僅僅是C#-CLR也必須支持這種限制,並且至少會鼓勵其他CLR語言也理解它。

我建議您通過兩種單獨的方法來解決此問題。 請注意,它們不能只是泛型方法的重載,因為重載不能僅因泛型類型約束而有所不同。 如果您不介意為實現接口的值類型裝箱,則可以使用以下方法進行重載:

internal void DoSomething(ISomething something)
{
}

internal void DoSomething(ISomethingElse somethingElse)
{
}

...盡管盡管如此,如果您傳入一個表達式是同時實現兩個接口的類型的值,則最終將導致過載歧義。

或者,只需給這兩種方法取不同的名稱。

編譯器必須在編譯時驗證所有約束,並且不能調用方法來進行驗證。

您可以在where約束中指定的唯一內容是:

  • new() -需要無參數構造函數
  • class -必須是引用類型
  • struct必須為值類型
  • SomeBaseClass
  • ISomeInterface
  • T : U必須是,可以繼承或實現其他通用參數之一

有關更多信息,請參見C#編程指南-類型參數的約束

至於為什么,您永遠不必回答“我認為沒有任何理由使它起作用”。 您必須從相反的方向開始,“為什么要這樣做”,然后提出足夠合理可行的方案和要求,以使其值得實施。 參見Eric Gunnerson的減100分

要在代碼中解決此問題,您應該從一個公共接口派生兩個接口,並在其上添加約束。

如果兩個接口沒有共同點,那么我首先質疑實際上添加約束的好處。

例如,如果您的代碼要在與泛型類型/方法一起使用的對象上調用方法,那么顯然兩個接口必須對該方法的含義具有相同的概念,而唯一的方法是在通用基本接口中定義的方法。 兩個接口碰巧聲明了具有相同簽名的相同方法或屬性,但並沒有使其成為相同的方法。

話雖如此,您確定這里甚至需要泛型嗎?

只聲明兩個方法,每個方法采用一個這樣的接口怎么樣?

internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)

編譯器使用通用約束來確定通用方法中T上可用的操作-因此允許or表達式將不是類型安全的。 例如,您有兩個接口IFirstISecond

public interface IFirst
{
    void First();
}

public interface ISecond
{
    void Second();
}
internal void DoSomething<T>(T workWithThis) where T : IFirst or ISecond
{
    //How to call this method if the type is ISecond
    workWithThis.First();
    //How to call this method if the type is IFirst
    workWithThis.Second();
}

您可以定義一個包含所有接口的空接口。

請記住,在C#接口中可以具有多個繼承。

例如:

public interface IHolder : ISomething, ISomethingElse 
{

}

對於通用

internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}

暫無
暫無

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

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