Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# i可比较和i可比较<;T>;_C#_.net_Icomparable - Fatal编程技术网

C# i可比较和i可比较<;T>;

C# i可比较和i可比较<;T>;,c#,.net,icomparable,C#,.net,Icomparable,我应该同时实现IComparable和泛型IComparable?如果我只实现其中一个,是否有任何限制 是的,您应该同时实现这两个功能 如果实现一个,任何依赖于另一个的代码都将失败 有很多代码使用IComparable或IComparable,但不能同时使用这两种代码,因此实现这两种代码可以确保您的代码能够与此类代码一起工作。而IEquatable通常不应由未密封的类来实现,由于除非实现简单地调用Object.Equals(在这种情况下,它将是无意义的),否则这种派生在继承中会起到奇怪的作用,因

我应该同时实现
IComparable
和泛型
IComparable
?如果我只实现其中一个,是否有任何限制

是的,您应该同时实现这两个功能

如果实现一个,任何依赖于另一个的代码都将失败

有很多代码使用
IComparable
IComparable
,但不能同时使用这两种代码,因此实现这两种代码可以确保您的代码能够与此类代码一起工作。

而IEquatable通常不应由未密封的类来实现,由于除非实现简单地调用Object.Equals(在这种情况下,它将是无意义的),否则这种派生在继承中会起到奇怪的作用,因此泛型IComparable会出现相反的情况。Object.Equals和IEquatable的语义意味着,无论何时定义IEquatable,其行为都应该反映Object.Equals的行为(除了可能更快和避免装箱)。当被视为DerivedFoo类型时比较为相等的两个DerivedFoo类型的对象在被视为Foo类型的对象时也应比较为相等,反之亦然。另一方面,当被视为类型DerivedFoo时排名不平等的两个DerivedFoo类型的对象在被视为类型Foo时排名相等,这是完全可能的。确保这一点的唯一方法是使用IComparable

例如,假设有一个类SchedulerEvent,其中包含ScheduledTime(类型DateTime)和ScheduledAction(类型MethodInvoker)字段。该类包括子类型SchedulerEventWithMessage(添加string类型的消息字段)和SchedulerEventWithGong(添加Double类型的GongVolume字段)。SchedulerEvent类根据ScheduledTime有一个自然的顺序,但是对于彼此无序的事件来说,完全可能是不相等的。SchedulerEventWithMessage和SchedulerEventWithGong类之间也有自然的顺序,但与SchedulerEvent类的项相比则没有

假设有两个ScheduleRevents,消息事件X和Y被同时调度,但X.消息是“aardvark”,Y.消息是“zymurgy”。((IComparable)X)。CompareTo(Y)应报告零(因为事件的时间相等),但((IComparable)X)。CompareTo(Y)应返回负数(因为“aardvark”在“zymurgy”之前排序)。如果类没有这样做,则很难或不可能对包含SchedulerEventWithMessage和SchedulerEventWithGong对象的混合列表进行一致排序


顺便说一句,有人可能会认为,让IEquatable compare对象的语义仅以T类型的成员为基础是有用的,例如,IEquatable将检查ScheduledTime和ScheduledAction是否相等,但即使应用于SchedulerEventWithMessage或SchedulerEventWithGong,也不会检查消息或卷属性。事实上,对于一个IEquatable方法来说,这些语义是有用的,我更喜欢这种语义,但有一个问题:Comparer.Default.GetHashCode(T)总是调用同一个函数Object.GetHashCode()不考虑类型T。这极大地限制了IEquatable使用不同类型T改变其行为的能力。

Oded正确地认为您应该同时实现这两种类型,因为存在只依赖其中一种实现的集合和其他类

但这里有一个技巧:IComparable不应该抛出异常,而IComparable应该抛出异常。在实现IComparable时,您负责确保T的所有实例都可以相互比较。这也包括null(将null视为小于T的所有非null实例,这样就可以了)

但是,general IComparable接受System.Object,您不能保证所有可能的对象都可以与t的实例进行比较。因此,如果您将一个非t实例传递给IComparable,只需抛出System.ArgumentException即可。否则,将调用路由到IComparable实现

以下是一个例子:

public class Piano : IComparable<Piano>, IComparable
{
    public int CompareTo(Piano other) { ... }
    ...
    public int CompareTo(object obj)
    {

        if (obj != null && !(obj is Piano))
            throw new ArgumentException("Object must be of type Piano.");

        return CompareTo(obj as Piano);

    }
}
公共课钢琴:我可比,我可比
{
公共国际比较(钢琴其他){…}
...
公共整数比较(对象对象对象)
{
如果(obj!=null&&!(obj是钢琴))
抛出新ArgumentException(“对象必须是Piano类型”);
返回比较器(obj作为钢琴);
}
}

这个例子是一篇长得多的文章的一部分,这篇文章包含了对副作用的广泛分析,在实现IComparable时您应该注意这些副作用:

@David-
IComparable
肯定被一些框架代码使用。我相信
Array.Sort
ArrayList.Sort
会使用它。好吧,真令人失望。如果能够忘记非通用的.net曾经存在过,那该多好啊。是我还是第一句和最后一句是矛盾的?@Henk我看不出矛盾。我也看不到矛盾。最后一句重申,如果不同时实现这两个功能,代码可能会中断。您只需为
IComparable
编写代码即可。通过将实际比较委托给通用实现,您可以免费获得
IComparable