简体   繁体   中英

I have a class A<T> : IEnumerable<T>, I want to add IEquatable<A<T>> if T : IEquatable<T>. How can I do that and keep the IEnumerable as well?

I have a Tree-type class Foo<T> with its interface IFoo<T> .

I want Foo<T> to be able to implement IEquatable<Foo<T>> when T : IEquatable<T> (or more generally if T : I<T> i might want Foo<T> : I<Foo<T>> in addition of other implemented interfaces) .

I tried the pseudo-following code :

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) { ... }
}      

So now I have succesfully implemented Equals (I also overrided the geniric Equals, etc.).

But FooTwo<T> now does not implement IEnumerable<IFooTwo<T>> (instead it implements IEnumerable<IFoo<T>> ).

So I have two questions :

  1. Is there a better way for me to organize my code in order to achieve my goal (if T : IEquatable<T> I want to be able to implement IEquatable<Foo<T>> for Foo<T> ) ? A sort of conditional where .
  2. How can I make FooTwo<T> implements IEnumerable <FooTwo<T>> using Foo<T> IEnumerable implementation in a quick and easy way ?

edit :

In the special case of IEquatable<Foo<T>> , I have a simple answer for question 1. I can test if T:IEquatable<T> and change my implementation of IEquatable<Foo<T>> if needed. However I am still wondering how to do it in a more general case.

For question 1, you should think about whether you really need this. IEquatable<T> mostly exists for performance reasons relating to value types . In your case, there shouldn't really be any reason that you need to make sure you're using the IEquatable equals rather than the object one. This is what, for example, Tuple<T> does. Then you can just have a single interface with no constraint:

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

For question 2, you may not need this either. IEnumerable<T> is covariant , meaning that if you have an IEnumerable<A> , you can assign this to a variable of type IEnumerable<B> , as long as A can be assigned to B . In your case, this means if you have, eg, a method that takes an IEnumerable<IFoo<T>> will also accept an IEnumerable<IFooTwo<T>> since IFooTwo<T> : IFoo<T>

However, if you want to have, say, a class MyFoo<T> : IFoo<T> to be of type IEnumerable<MyFoo<T>> , there's no way to do that automatically. This is because it's perfectly possible to have a valid implementation of IEnumerable<IFoo<T>> which isn't also an implementation of IEnumerable<MyFoo<T>> . You should probably treat this requirement as a design smell and try to avoid it.

Since what you're essentially doing is trying to have some IFoo<T> objects be IEquatable<T> and some not, and that's clearly at odds with the type system, I'd avoid IEquatable<T> entirely. Use IEqualityComparer<T> . Simply provide a method that creates an IEqualityComparer<IFoo<T>> when given an IEqualityComparer<T> (or using the default comparer for T , if you want).

By doing this none of the IFoo<T> objects are obligated to compare themselves, but anyone is able to create a means of comapring IFoo<T> objects as long as they know how to compare the underlying objects.

This also removes the need for multiple implementations of IFoo<T> entirely, simplifying the entire code base dramatically, and removing your other problem entirely.

How can I make FooTwo<T> implements IEnumerable<FooTwo<T>> using Foo<T> IEnumerable implementation in a quick and easy way?

(If you choose to not follow my suggestion for changing how you handle equality:)

If you know that all of the items in the sequence are in fact of the correct type, you can simply use Cast<FooTwo<T>>() on the sequence.

If the items in the sequence aren't actually FooTwo<T> objects then you'll need to project the items into a new sequence, where you map each IFoo<T> item to a FooTwo<T> item.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM