Reputation: 856
Sometimes you want to implement an interface that looks like this:
public interface ITraversable<T> {
List<T> Children { get; }
}
But sometimes you need a different collection class like this:
public interface ITraversable<T> {
ObservableCollection<T> Children { get; }
}
But you don't want to repeat yourself, so you try this interface:
public interface ITraversable<T> {
IEnumerable<T> Children { get; }
}
But any implementing class that uses List or ObservableCollection will get an error:
Error CS0738 'Tester' does not implement interface member 'ITraversable.Children'. 'Tester.Children' cannot implement 'ITraversable.Children' because it does not have the matching return type of 'IEnumerable'.
Is it possible to create a single interface with a generic interface property that can be used by multiple concrete class implementations?
Upvotes: 1
Views: 729
Reputation: 271105
You can use an explicit interface implementation while still having the IEnumerable<T>
requirement:
public interface ITraversable<T> {
IEnumerable<T> Children { get; }
}
public class Implementer1<T>: ITraversable<T> {
List<T> Children { get; }
IEnumerable<T> ITraversable<T>.Children => Children;
}
public class Implementer2<T>: ITraversable<T> {
ObservableCollection<T> Children { get; }
IEnumerable<T> ITraversable<T>.Children => Children;
}
This will not give the error that there are two properties with the same name, nor will it cause infinite recursion, because explicit interface implementation are hidden, unless you are accessing it through the interface.
Upvotes: 3
Reputation: 856
This is one method I have found to implement a single interface with a generic interface that can be implemented by multiple concrete classes:
public interface ITraversable<T, out TEnumerable> where TEnumerable : IEnumerable<T> {
TEnumerable Children { get; }
}
This allows you to have different classes that use different concrete implementations of IEnumerable.
public class TestClass1 : ITraversable<TestClass1, List<TestClass1>> {
public List<TestClass1> Children { get; }
}
public class TestClass2 : ITraversable<TestClass2, ObservableCollection<TestClass2>> {
public ObservableCollection<TestClass2> Children { get; }
}
When implementing an interface, the types must match exactly. This is why you can't replace IEnumerable with List since they aren't the exact same type. However, if you specify the exact type as a generic parameter on the interface, you can then match the types exactly.
Upvotes: 0