我在C#中的泛型有问题,希望您能帮帮我。

public interface IElement { }

public interface IProvider<T> where T : IElement {
    IEnumerable<T> Provide();
}

到目前为止,这非常简单。我希望提供者返回特定元素的可枚举值。
接口(interface)的具体实现如下:

public class MyElement : IElement { }

public class MyProvider : IProvider<MyElement> {
    public IEnumerable<MyElement> Provide() {
        [...]
    }
}

但是现在当我想使用它时,问题就来了。这不会编译,因为它无法将MyProvider隐式转换为IProvider<IElement>:

IProvider<IElement> provider = new MyProvider();

尽管IProvider<IElement>MyProviderIProvider<MyElement>MyElement,但我必须对IElement进行强制转换。我可以通过使MyProvider也实现IProvider<MyElement>来避免转换,但是为什么它不能解析type参数中的层次结构?

编辑:根据Thomas的建议,我们可以使其在T中为协变的。但是,如果还有下面的其他方法,其中有T类型的参数,该怎么办?

public interface IProvider<T> where T : IElement {
    IEnumerable<T> Provide();
    void Add(T t);
}

最佳答案

如果仅使用对IProvider<IElement>的引用来访问在输出位置上具有T的方法,则可以将接口(interface)分为两个(请为它们找到更好的名称,例如unit的ISink<in T>):

public interface IProviderOut<out T> where T : IElement {
  IEnumerable<T> Provide();
}
public interface IProviderIn<in T> where T : IElement {
  void Add(T t);
}

您的类(class)同时实现了以下两种方法:
public class MyProvider : IProviderOut<MyElement>, IProviderIn<MyElement> {
  public IEnumerable<MyElement> Provide() {
    ...
  }
  public void Add(MyElement t) {
    ...
  }
}

但是现在您需要上联时使用协变接口(interface):
IProviderOut<IElement> provider = new MyProvider();

另外,您的界面可以从以下两者继承:
public interface IProvider<T> : IProviderIn<T>, IProviderOut<T>
  where T : IElement {
  // you can add invariant methods here...
}

然后您的类实现它:
public class MyProvider : IProvider<MyElement> ...

09-15 17:10