区别非常明显。请注意,您必须T
在方法(泛型方法)或包含类(泛型类,不能使用扩展方法)中定义。下面我称这两种方法1和2:
public static bool IsFoo1<T>(this IComparable<T> value, T other)
where T : IComparable<T>
{
return true;
}
public static bool IsFoo2<T>(this T value, T other)
where T : IComparable<T>
{
return true;
}
根据T
是值类型还是引用类型,存在差异。您可以通过使用约束where T : struct, IComparable<T>
或where T : class, IComparable<T>
.
通常使用任何类型T
:X
可能会声明
一些疯狂的类型IComparable<Y>
,其中Y
与X
.
使用值类型:
withIFoo1
第一个参数value
会被装箱,而value
inIFoo2
不会被装箱。值类型是密封的,逆变不适用于值类型,所以这是本例中最重要的区别。
使用参考类型:
使用 reference type T
,装箱不是问题。但请注意,它的类型参数IComparable<>
是逆变的(“ in
”)。如果某些非密封类实现,这很重要IComparable<>
。我使用了这两个类:
class C : IComparable<C>
{
public int CompareTo(C other)
{
return 0;
}
}
class D : C
{
}
使用它们,可以进行以下调用,其中一些是因为继承和/或逆变:
// IsFoo1
new C().IsFoo1<C>(new C());
new C().IsFoo1<C>(new D());
new D().IsFoo1<C>(new C());
new D().IsFoo1<C>(new D());
new C().IsFoo1<D>(new D());
new D().IsFoo1<D>(new D());
// IsFoo2
new C().IsFoo2<C>(new C());
new C().IsFoo2<C>(new D());
new D().IsFoo2<C>(new C());
new D().IsFoo2<C>(new D());
//new C().IsFoo2<D>(new D()); // ILLEGAL
new D().IsFoo2<D>(new D());
当然,在许多情况下,<C>
可以省略通用参数,因为它会被推断出来,但为了清楚起见,我将其包含在此处。