Dot-Net

通用約束是否應該優於使用介面作為參數類型?

  • August 20, 2010

考慮這個微不足道的函式:

public static bool IsPositive(IComparable<int> value)
{
   return value.CompareTo(0) > 0;
}

現在,如果我將一個傳遞int給這個方法,它就會被裝箱。因此,將上述方法定義如下不是更好嗎?

public static bool IsPositive<T>(T value) where T : IComparable<int>
{
   return value.CompareTo(0) > 0;
}

以這種方式使用通用約束,我可以實現與上面的程式碼完全相同的功能,另外還有一個好處是不需要裝箱(因為呼叫IsPositive<int>接受 type 的參數int)。

上面的範常式式碼顯然毫無意義。但我更廣泛的問題是:以後一種方式定義方法(使用通用約束而不是具有某種介面類型的參數)以避免潛在的值類型裝箱不是總是有意義的嗎?

我懷疑答案很可能是“是的,但它需要更多的輸入,並且在許多情況下遇到值類型的可能性很小,例如當方法接受 some 時IEnumerable<T>”。但我想知道這些方法之間是否存在更大的差異,而這些方法目前正在逃避我。

一個問題是通用約束實際上並不是簽名的一部分。如果你有 …

static T Method<T>(T value) where T : ICompareable<int>

… 和 …

static T Method<T>(T value) where T : IEnumerable<int>

…編譯器無法知道哪個是哪個。

並呼叫 Eric Lippert…

關於在參數傳遞對該方法的呼叫是否會導致裝箱的問題的評論存在一些混淆。

當您在其類型是帶有約束的類型參數的表達式上呼叫虛擬方法時,C# 編譯器會發出一條constrained.callvirt指令。正如人們所希望的那樣,這是正確的。拳擊只有在絕對必要時才會發生。

有關受限虛擬呼叫的精確裝箱語義的詳細資訊,請閱讀文件:

http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx

引用自:https://stackoverflow.com/questions/3525761