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 :
T : IEquatable<T>
I want to be able to implement IEquatable<Foo<T>>
for Foo<T>
) ? A sort of conditional where
. 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>
implementsIEnumerable<FooTwo<T>>
usingFoo<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.