当我想限制类型 T 具有可比性时,我应该使用:
where T : IComparable
或者
where T : IComparable<T>
如果#2有意义,我无法理解。任何人都可以解释有什么区别?
当我想限制类型 T 具有可比性时,我应该使用:
where T : IComparable
或者
where T : IComparable<T>
如果#2有意义,我无法理解。任何人都可以解释有什么区别?
IComparable 和 IComparable<> 之间的主要区别在于第一个是预泛型,因此允许您使用任何对象调用 compare 方法,而第二个强制它共享相同的类型:
IComparable - CompareTo(object other);
IComparable<T> - CompareTo(T other);
如果您不打算使用任何类型可能无法实现现代通用解决方案的旧 .net 1.0 库,我会选择第二个选项。您将获得性能提升,因为您将避免拳击,并且比较不需要检查类型匹配,您还将获得以最前沿的方式做事的温暖感觉......
为了解决 Jeff 的非常好的和相关的观点,我认为最好对泛型施加尽可能少的约束来执行任务。由于您完全控制了泛型内的代码,因此您知道您是否正在使用任何需要基本 IComparable 类型的方法。因此,考虑到他的评论,我个人会遵循以下规则:
如果您不希望泛型使用仅实现 IComparable 的任何类型(即遗留 1.0 代码)并且您没有从泛型内部调用任何依赖于 IComparable 参数的方法,则仅使用 IComparable<> 约束。
如果您使用仅实现 IComparable 的类型,则仅使用该约束
如果您正在使用需要 IComparable 参数的方法,但不使用仅实现 IComparable 的类型,那么当您使用接受泛型类型的方法时,使用 Jeff 的答案中的两个约束将提高性能。
为了扩展第三条规则 - 让我们假设您正在编写的课程如下:
public class StrangeExample<T> where ... //to be decided
{
public void SortArray(T[] input)
{
Array.Sort(input);
}
public bool AreEqual(T a, T b)
{
return a.CompareTo(b) == 0;
}
}
我们需要决定对其施加什么限制。SortArray 方法调用 Array.Sort,它需要传入的数组包含实现 IComparable 的对象。因此我们必须有一个 IComparable 约束:
public class StrangeExample<T> where T : IComparable
现在该类将编译并正常工作,因为 T 数组对 Array.Sort 有效,并且接口中定义了有效的 .CompareTo 方法。但是,如果您确定不想将类与不实现 IComparable<> 接口的类型一起使用,则可以将约束扩展到:
public class StrangeExample<T> where T : IComparable, IComparable<T>
这意味着当 AreEqual 被调用时,它将使用更快、更通用的 CompareTo 方法,您将看到性能优势,但代价是无法将它与旧的 .NET 1.0 类型一起使用。
另一方面,如果您没有 AreEqual 方法,那么 IComparable<> 约束没有任何优势,因此您不妨放弃它 - 无论如何您只是在使用 IComparable 实现。
您可能需要这两个约束,如:
where T : IComparable, IComparable<T>
这将使您的类型与IComparable
接口的更多用户兼容。的通用版本将有助于避免在值类型时装箱,IComparable
并允许接口方法的更强类型的实现。支持两者可确保无论其他对象要求哪个接口,您的对象都可以遵守并因此很好地互操作。IComparable<T>
T
例如,Array.Sort
并ArrayList.Sort
使用IComparable
,而不是IComparable<T>
。
IComparable<T>
允许比较器是强类型的。
你可以有
public int CompareTo(MyType other)
{
// logic
}
反对
public int CompareTo(object other)
{
if (other is MyType)
// logic
}
例如,下一个示例女巫实现了这两个接口:
public class MyType : IComparable<MyType>, IComparable
{
public MyType(string name, int id)
{ Name = name; Id = id; }
public string Name { get; set; }
public int Id { get; set; }
public int CompareTo(MyType other)
{
if (null == other)
throw new ArgumentNullException("other");
return (Id - other.Id > 0 ? 1 : 0);
}
public int CompareTo(object other)
{
if (null == other)
throw new ArgumentNullException("other");
if (other is MyType)
return (Id - (other as MyType).Id > 0 ? 1 : 0);
else
throw new InvalidOperationException("Bad type");
}
}
MyType t1 = new MyType("a", 1);
MyType t2 = new MyType("b", 2);
object someObj = new object();
// calls the strongly typed method: CompareTo(MyType other)
t1.CompareTo(t2);
// calls the *weakly* typed method: CompareTo(object other)
t1.CompareTo(someObj);
如果MyType
仅使用 实现IComparable<MyType>
,则第二个compareTo(someObj)
是编译时错误。这是强类型泛型的优点之一。
另一方面,框架中有一些方法需要非泛型IComparable
like Array.Sort
。在这些情况下,您应该考虑像本示例中那样实现这两个接口。
这是两个不同的接口。在 .NET 2.0 之前没有泛型,所以只有IComparable
. .NET 2.0 出现了泛型,并且可以将IComparable<T>
. 他们做的完全一样。基本上 IComparable 已经过时了,尽管大多数图书馆都承认这两者。
要使您的代码真正兼容,请同时实现两者,但要一个调用另一个,这样您就不必编写相同的代码两次。
我将使用第二个约束,因为这将允许您引用接口的强类型成员。如果您选择第一个选项,那么您将不得不强制转换以使用接口类型。