2016-01-06 40 views
3

我有一个树型的类Foo<T>与它的接口IFoo<T>我有一个类A <T>:IEnumerable <T>,我想添加IEquatable <A<T>>如果T:IEquatable <T>。我该怎么做,并保持IEnumerable呢?

我想Foo<T>能够实现IEquatable<Foo<T>>T : IEquatable<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(我也overrided的geniric平等相待,等等)。

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

所以我有两个问题:

  1. 有没有更好的办法,我来组织我的代码以实现我的目标(如果T : IEquatable<T>我希望能够实现IEquatable<Foo<T>>Foo<T>)?一种有条件的where
  2. 如何使用 Foo<T> IEnumerable快速轻松地实现FooTwo<T> implements IEnumerable <FooTwo<T>>

编辑:

IEquatable<Foo<T>>的特殊情况下,我有疑问1.一个简单的答案我可以测试是否T:IEquatable<T>并根据需要更改我的执行IEquatable<Foo<T>>。不过,我仍然想知道如何在更一般的情况下做到这一点。

+2

你如何重新实现'IEnumerable >'而不是'IEnumerable >'? –

+0

你是对的,编辑 –

+0

**请**注意编辑问题时的预览窗格,尤其是当您试图讨论泛型类型参数时。我已经修复了一次你的代码,我没有心情再次为你的修改做这件事(请尝试阅读,因为它目前显示,并看看它有多少意义) –

回答

1

因为你实质上是在试图让一些IFoo<T>对象是IEquatable<T>而有些不是,这显然与类型系统不一致,所以我完全避免IEquatable<T>。使用IEqualityComparer<T>。只需提供一种方法,在给定IEqualityComparer<T>(或使用默认比较器T,如果需要)时创建IEqualityComparer<IFoo<T>>

通过这样做,任何IFoo<T>对象都有义务进行比较,但只要知道如何比较基础对象,任何人都可以创建共同对象的方法。

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

我怎样才能让FooTwo<T>器具IEnumerable<FooTwo<T>>使用一个快速简便的方法 Foo<T> IEnumerable实施?

(如果您选择不跟随我的建议改变你如何处理平等:)

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

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

2

对于问题1,你应该考虑你是否真的需要这个。 IEquatable<T>mostly exists for performance reasons relating to value types。在你的情况下,不应该有任何理由,你需要确保你使用的是平等而不是目标。例如,这是Tuple<T>所做的。那么你可以只有一个没有约束的接口:

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

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

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

+0

我现在看到的问题1,我可以测试如果T:IEquatable 并更改我的IEquatable > .Equals实现功能。如果它是另一个接口而不是IEquatable呢? 但对于问题2,我无法列举我想要做的FooTwo 类为FooTwo 。 (例如'foreach(FooTwo t x in)'将会失败,x'FooTwo ' –

+0

@ CelestinSaint-Loup那么你总是可以在'FooTwo'声明中添加':IEnumerable >'显然不会当'x'工作时(在你的例子中)有静态类型'IFooTwo'而不是'FooTwo',但这是不可能的。 –

+0

@ CelestinSaint-Loup但是有一个原因,你发现这些东西很难 - 你正在尝试对照类型系统而不是使用它,你应该检查你的设计,试着看看你能否摆脱这些要求 –

相关问题