我有一个a<;T>;: ;IEnumerable<;T>;,我想添加IEquatable<;

本文关键字:lt gt 添加 IEquatable IEnumerable 有一个 #160 | 更新日期: 2023-09-27 18:29:22

我有一个Tree类型的类Foo<T>及其接口IFoo<T>

我希望Foo<T>能够在T : IEquatable<T>时实现IEquatable<Foo<T>>(或者更一般地,如果T : I<T>,我可能希望Foo<T> : I<Foo<T>>以及其他实现的接口)

我尝试了以下伪代码:

public interface IFoo<T> : IEnumerable<IFoo<T>>
...

public class Foo<T> : IFoo<T>
...

public interface IFooTwo<T> : IFoo<T>, IEquatable<IFooTwo<T>>
    where T : IEquatable<T>
...
public class FooTwo<T> : IFooTwo<T> {
... // I implement Equals
    public bool NewMethod(FooTwo<T> Other) { ... }
}      

所以现在我已经成功地实现了Equals(我还推翻了geniric Equals等)

但是FooTwo<T>现在不实现IEnumerable<IFooTwo<T>>(而是实现IEnumerable<IFoo<T>>)。

所以我有两个问题:

  1. 有没有更好的方法来组织我的代码以实现我的目标(如果T : IEquatable<T>,我希望能够为Foo<T>实现IEquatable<Foo<T>>)?一类条件CCD_ 15
  2. 如何使用使FooTwo<T>实现IEnumerable <FooTwo<T>>Foo<T> IEnumerable的快速简便实现

编辑:

IEquatable<Foo<T>>的特殊情况下,我对问题1有一个简单的答案。我可以测试是否为T:IEquatable<T>,并在需要时更改IEquatable<Foo<T>>的实现。然而,我仍然想知道如何在更普遍的情况下做到这一点。

我有一个a<;T>;: ;IEnumerable<;T>;,我想添加IEquatable<;

对于问题1,您应该考虑是否真的需要这个。CCD_ 22的存在主要是由于与值类型相关的性能原因。在您的情况下,应该没有任何理由需要确保您使用的是IEquatable equals,而不是对象。例如,Tuple<T>就是这样做的。然后你就可以有一个没有限制的单一界面:

public interface IFoo<T> : IEnumerable<IFoo<T>>, IEquatable<IFoo<T>>

对于问题2,您可能也不需要这个。IEnumerable<T>是协变的,这意味着如果您有IEnumerable<A>,您可以将其分配给类型为IEnumerable<B>的变量,只要A可以分配给B即可。在您的情况下,这意味着如果您有,例如,一个采用IEnumerable<IFoo<T>>的方法也将接受IEnumerable<IFooTwo<T>>,因为IFooTwo<T> : IFoo<T>

但是,如果您想使类MyFoo<T> : IFoo<T>的类型为IEnumerable<MyFoo<T>>,则无法自动执行此操作。这是因为完全有可能拥有IEnumerable<IFoo<T>>的有效实现,而不是IEnumerable<MyFoo<T>>的实现。您可能应该将此需求视为一种设计气味,并尽量避免它。

由于您主要要做的是尝试让一些IFoo<T>对象是IEquatable<T>,而另一些对象不是,这显然与类型系统不一致,因此我会完全避免IEquatable<T>。使用IEqualityComparer<T>。只需提供一个方法,在给定IEqualityComparer<T>时创建IEqualityComparer<IFoo<T>>(如果需要,可以使用T的默认比较器)。

通过这样做,任何IFoo<T>对象都没有义务进行自身比较,但只要知道如何比较底层对象,任何人都可以创建一种方法来管理IFoo<T>对象。

这也完全消除了对IFoo<T>的多个实现的需要,极大地简化了整个代码库,并完全消除了您的其他问题。

如何使用使FooTwo<T>实现IEnumerable<FooTwo<T>>Foo<T> IEnumerable的快速简便实现?

(如果你选择不按照我的建议改变你处理平等的方式:)

如果您知道序列中的所有项目实际上都是正确的类型,那么您可以简单地在序列上使用Cast<FooTwo<T>>()

如果序列中的项目实际上不是FooTwo<T>对象,那么您需要将这些项目投影到一个新的序列中,在该序列中将每个IFoo<T>项目映射到一个FooTwo<T>项目。