[英]Unbounded type parameters in Generics C#
我是泛型新手,我開始從MSDN Library學習泛型
我無法理解以下有關無界類型參數的要點。
不具有約束,如類型參數
T
在public class SampleClass<T>{}
被稱為無界類型參數。 無限類型參數具有以下規則:
- 不能使用
!=
和==
運算符,因為不能保證具體類型參數將支持這些運算符。- 您可以將其與
null
進行比較。 如果將無界參數與null
進行比較,如果type參數為值類型,則比較將始終返回false
。
我沒有發現以上幾點的任何例子。 如果有人給我榜樣來理解要點,那將是很好的。
注意:我的問題是關於!=
和==
運算符的使用...為什么我們不能在無界類型中使用這些運算符,以及如果將Unbounded參數與null
進行比較,為什么總是返回false
讓我們假設一下這是可能的:
public class C
{
public bool AreEqual<T>(T first, T second)
{
return first == second;
}
}
現在假設有一個名為F的struct
,它沒有實現==
運算符(默認情況下沒有任何結構)。 這里應該怎么辦?
F first = new F();
F second = new F();
var c = new C();
Console.WriteLine(c.AreEqual(first, second));
值類型沒有實現==
,並且我們不能Object.ReferenceEquals
因為它還是值類型。 這就是為什么編譯器不允許您這樣做。
類型參數可以具有約束,例如: where T: BaseClass
。 這意味着T必須從BaseClass
繼承。 如果類型參數沒有此類約束,則稱為無界。
您引用的文檔有兩點:
不能使用!=和==運算符,因為不能保證具體類型參數將支持這些運算符。
這意味着編譯器無法知道類型T
具有運算符==
和!=
。 SampleClass<int>
可以工作,但是如果MyType
沒有實現運算符,則SampleClass<MyType>
可能不起作用。 由於T
是無界的,這意味着編譯器無法知道期望的結果,因此必須采取限制性最強的情況。
您可以比較為null。 如果將無界參數與null進行比較,則如果type參數為值類型,則比較將始終返回false。
這只是指出您可以將其與null進行比較,但是如果T
是不可為null的類型,則它總是返回false。 考慮以下:
int i = 0;
if (null == i)
{
}
這將產生一個編譯器警告,因為您沒有賦予i
值來使表達式為true
。
我的問題是關於!=和==運算符的使用...為什么我們不能在無界類型中使用這些運算符
他們是什么意思? 通常!=
和==
表示“不等於”和“等於”,但是其確切含義取決於它們是值類型還是引用類型(以及它們是否已重載了這些運算符,但這也不適用)許多有界類型)。 在沒有約束的情況下,至少!=
和==
具有任何意義。
以及為什么將Unbounded參數與null相比總是返回false。
您看錯了。 實際上,您之前引用的是:
如果type參數為值類型,則比較將始終返回false。 [強調我的]
這實際上是不正確的,在這種情況下,可為空的值類型可以返回true
:
public class Test<T>
{
public bool IsNull(T val)
{
return val == null;
}
}
與上面的代碼,我們得到true
,如果我們所說的new Test<int?>().IsNull(null)
和假,如果我們所說的new Test<int?>().IsNull(1)
對於除Nullable
類型之外的任何其他值類型,我們將得到false
因為這是唯一可能的值。 Nullable<T>
以外的其他值類型不能為null。
值得注意的是,抖動將優先於此,因為當它為該方法生成機器代碼時,它將知道val == null
始終為false並將代碼替換為常量false
。 如果存在分支,則無需將其分支。 考慮:
public string CallToString(T val)
{
if (val == null)
return null;
else
return val.ToString();
}
如果為非空值類型的T
引用了此方法,則它與代碼曾經是相同的:
public string CallToString(T val)
{
return val.ToString();
}
因為抖動知道永遠不會碰到第一個分支。 類似地,考慮Enumerable.Max()
。 此方法對可為空類型的空序列返回null
,否則引發異常。 對於特定的覆蓋,這很簡單:例如,在這種情況下, Enumerable.Max(this IEnumerable<decimal> source)
Enumerable.Max(this IEnumerable<decimal?> source)
具有返回null的代碼,而Enumerable.Max(this IEnumerable<decimal> source)
具有拋出的代碼。 但是對於一般情況,它需要涵蓋兩種情況。 因此,它這樣做:
public static TSource Max<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default(TSource);
if (value == null)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
do
{
if (!e.MoveNext()) return value;
value = e.Current;
} while (value == null);
while (e.MoveNext())
{
TSource x = e.Current;
if (x != null && comparer.Compare(x, value) > 0) value = x;
}
}
}
else
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext()) throw Error.NoElements();
value = e.Current;
while (e.MoveNext())
{
TSource x = e.Current;
if (comparer.Compare(x, value) > 0) value = x;
}
}
}
return value;
}
當為可空類型(引用類型為Nullable<T>
抖動時,抖動會事先知道default(TSource) == null
始終為true,這意味着它與抖動相同。
public static TSource Max<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = null;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
do
{
if (!e.MoveNext()) return value;
value = e.Current;
} while (value == null);
while (e.MoveNext())
{
TSource x = e.Current;
if (x != null && comparer.Compare(x, value) > 0) value = x;
}
}
return value;
}
如果類型是不可為空的值類型,則它與被添加的值相同:
public static TSource Max<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default(TSource);
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext()) throw Error.NoElements();
value = e.Current;
while (e.MoveNext())
{
TSource x = e.Current;
if (comparer.Compare(x, value) > 0) value = x;
}
}
return value;
}
因此,非空值類型和null
之間的==
始終為false
(而!=
始終為true
)不僅是一種限制,它實際上還有助於允許我們以不同的方式覆蓋nullable和nonnullable類型。 ,並且在刪除特定情況下不使用的分支時,抖動將表現得很明智。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.