[英]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.