【问题标题】:Use a Compatible Concrete Type When Implementing Interface With a Generic Interface Property使用通用接口属性实现接口时使用兼容的具体类型
【发布时间】:2021-03-08 01:24:12
【问题描述】:

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

public interface ITraversable<T> {

    List<T> Children { get; }

}

但有时您需要像这样的不同集合类:

public interface ITraversable<T> {

    ObservableCollection<T> Children { get; }

}

但你不想重复自己,所以你试试这个界面:

public interface ITraversable<T> {

    IEnumerable<T> Children { get; }

}

但是任何使用 List 或 ObservableCollection 的实现类都会报错:

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

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

【问题讨论】:

    标签: c# class generics interface


    【解决方案1】:

    您可以使用显式接口实现同时仍然具有IEnumerable&lt;T&gt; 要求:

    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;
    }
    

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

    【讨论】:

      【解决方案2】:

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

      public interface ITraversable<T, out TEnumerable> where TEnumerable : IEnumerable<T> {
      
          TEnumerable Children { 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; }
      
      }
      

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

      【讨论】:

      • 我更喜欢 Sweepers 回答的原因是,虽然这使它可以编译,但现在所有使用 ITraversable 接口的东西都需要将第二个泛型类型参数定义为 IEnumerable&lt;T&gt;。因此,您的代码将充满ITraversable&lt;TestClass2, IEnumerable&lt;TestClass2&gt;&gt; input 之类的内容,而无法使用ITraversable&lt;TestClass2&gt; input。从您自己的问题“具有通用接口属性”中,但您将该接口更改为现在需要多个通用类型参数
      猜你喜欢
      • 2013-03-07
      • 1970-01-01
      • 2014-08-22
      • 1970-01-01
      • 2022-11-28
      • 2017-04-16
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      相关资源
      最近更新 更多