簡體   English   中英

通用類型約束禁止某些類型?

[英]Generic type constraint to prohibit certain types?

我想創建一個通用方法:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)

我的代碼中有很多變量,包括List<T>IEnumerable<T>xxxCollectionT[]等......這個方法也有一個重載,它將采用不可枚舉的值。 是否可以在類型參數約束中禁止特定類(如string )?

我已經創建了一個像這樣的重載:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, object value)

這種重載對於處理單個值很有用,但處理值集合需要稍微不同的實現。 但是, string實現IEnumerable所以我的所有字符串變量都將被發送到錯誤的重載,除非我可以告訴編譯器應該排除它們。

不可以。 通用類型參數約束只能強制執行約束而不是約束。

運行時類型檢查可能是要走的路:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
{
    if (typeof(T) == typeof(string))
    {
        throw new IllegalOperationException(...);
    }
}

如果要傳遞給方法的所有類型都從相同的基類繼承,或者實現相同的接口,則可以使用jrummell建議的單個約束來強制繼承。

雖然它更不優雅,但如果你想支持異構類型,另一種方法就是提供足夠的重載來處理你的特定用例:

// supports int, float, DateTime, etc.
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<int> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<float> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<DateTime> value)

// supports implementations of MyInterface
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<IMyInterface> value)

在上面的示例中,您將無法調用MyMethod<string>因為它不滿足任何提供的類型約束。 請注意,您不能使用類型約束,因為它們不是方法簽名的一部分。

假設您只想將此擴展用於模型類型,您可以創建一個Model基類並將T限制為實現它的類型。

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
    where T : ModelBase

考慮到你打算處理string意圖,你不能使用約束而你不需要它們。

給定您接受類型object的現有方法,類型為string的參數將導致您提出的新重載,因為IEnumerable<char>是一個比object更好的匹配。 但是,您不必放棄重載的想法,也不需要求助於運行時檢查。 只需為string創建一個額外的重載。 通過使編譯器的場景更加容易,可以在objectIEnumerable<T>之間執行整個決策。

特定

void Foo(object argument)
{
    Console.WriteLine("object");
}

void Foo<T>(IEnumerable<T> argument)
{
    Console.WriteLine("enumerable T");
}

void Foo(string argument)
{
    Console.WriteLine("string");
}

一個方法調用列表

Foo("hello");
Foo(1);
Foo(new int[] { 1 });

產生輸出

string
object
enumerable T

然后,您可以在單個位置進一步強制將字符串強制轉換為對象重載。

void Foo(string argument)
{
    // Console.WriteLine("string");
    Foo((object)argument);
}

抱歉不行。

您只能指定以下類型的約束:

where T : struct               // T must be a value type
where T : class                // T must be a reference type
where T : new()                // T must have a parameterless constructor
where T : <base class name>    // T must inherit from <base class>
where T : <interface name>     // T must implement <interface>
where T : U                    // T must inherit from U, where U is another
                               // generic parameter

參考: 類型參數的約束

現在,您可以使用其中一些來限制,但不能鎖定類型,僅指定您允許的類型,例如接口實現約束。

您可以使用接口或基類約束來明確說“我允許的類型必須具有以下特征”。 我會說這將是你最好的選擇。

你確定仿制葯是正確的工具嗎?

暫無
暫無

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

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