C# 使用泛型接口属性实现接口时,请使用兼容的具体类型

C# 使用泛型接口属性实现接口时,请使用兼容的具体类型,c#,class,generics,interface,C#,Class,Generics,Interface,有时,您希望实现如下所示的接口: public interface ITraversable<T> { List<T> Children { get; } } public interface ITraversable<T> { ObservableCollection<T> Children { get; } } public接口不可用{ 列出子项{get;} } 但有时您需要一个不同的集合类,如下所示: publi

有时,您希望实现如下所示的接口:

public interface ITraversable<T> {

    List<T> Children { get; }

}
public interface ITraversable<T> {

    ObservableCollection<T> Children { get; }

}
public接口不可用{
列出子项{get;}
}
但有时您需要一个不同的集合类,如下所示:

public interface ITraversable<T> {

    List<T> Children { get; }

}
public interface ITraversable<T> {

    ObservableCollection<T> Children { get; }

}
public接口不可用{
可观察收集子项{get;}
}
但您不想重复自己的操作,因此请尝试以下界面:

public interface ITraversable<T> {

    IEnumerable<T> Children { get; }

}
public接口不可用{
IEnumerable子项{get;}
}
但是任何使用List或ObservableCollection的实现类都会得到一个错误:

错误CS0738“Tester”未实现接口成员“ITraversable.Children”Tester.Children无法实现“ITraversable.Children”,因为它没有匹配的返回类型“IEnumerable”


是否可以创建一个具有泛型接口属性的接口,该属性可由多个具体类实现使用?

这是我发现的一种方法,可以使用可由多个具体类实现的泛型接口实现单个接口:

public interface ITraversable<T, out TEnumerable> where TEnumerable : IEnumerable<T> {

    TEnumerable Children { get; }

}
公共接口ITraversable其中TEnumerable:IEnumerable{
可数子项{get;}
}
这允许您拥有使用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; }

}
公共类TestClass1:ITraversable{
公共列表子项{get;}
}
公共类TestClass2:ITraversable{
公共可观察集合子项{get;}
}

实现接口时,类型必须完全匹配。这就是为什么不能将IEnumerable替换为List,因为它们不是完全相同的类型。但是,如果将确切类型指定为接口上的泛型参数,则可以精确匹配这些类型。

这是我发现的一种方法,可以使用可由多个具体类实现的泛型接口实现单个接口:

public interface ITraversable<T, out TEnumerable> where TEnumerable : IEnumerable<T> {

    TEnumerable Children { get; }

}
公共接口ITraversable其中TEnumerable:IEnumerable{
可数子项{get;}
}
这允许您拥有使用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; }

}
公共类TestClass1:ITraversable{
公共列表子项{get;}
}
公共类TestClass2:ITraversable{
公共可观察集合子项{get;}
}

实现接口时,类型必须完全匹配。这就是为什么不能将IEnumerable替换为List,因为它们不是完全相同的类型。但是,如果将确切类型指定为接口上的通用参数,则可以精确匹配这些类型。

您可以使用显式接口实现,同时仍具有
IEnumerable
要求:

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;
}
public接口不可用{
IEnumerable子项{get;}
}
公共类实现者1:可撤销{
列出子项{get;}
IEnumerable.Children=>Children;
}
公共类实现器2:可撤销{
可观察收集子项{get;}
IEnumerable.Children=>Children;
}

这不会产生两个同名属性的错误,也不会导致无限递归,因为显式接口实现是隐藏的,除非您通过接口访问它。

您可以使用显式接口实现,同时仍然具有
IEnumerable
要求:

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;
}
public接口不可用{
IEnumerable子项{get;}
}
公共类实现者1:可撤销{
列出子项{get;}
IEnumerable.Children=>Children;
}
公共类实现器2:可撤销{
可观察收集子项{get;}
IEnumerable.Children=>Children;
}

这不会导致有两个同名属性的错误,也不会导致无限递归,因为显式接口实现是隐藏的,除非您通过接口访问它。

我更喜欢扫掠器的原因是,虽然这会使它编译,现在,所有使用
ITraversable
接口的操作都需要将第二个泛型类型参数定义为
IEnumerable
。因此,您的代码将充满这样的内容
ITraversable input
,而不是能够使用
ITraversable input
。从您自己的问题“具有泛型接口属性”,但您将该接口更改为现在需要多个泛型类型参数。我更喜欢扫掠器的原因是,虽然这会使其编译,现在,所有使用
ITraversable
接口的操作都需要将第二个泛型类型参数定义为
IEnumerable
。因此,您的代码将充满这样的内容
ITraversable input
,而不是能够使用
ITraversable input
。从您自己的问题“具有泛型接口属性”,但您将该接口更改为现在需要多个泛型类型参数