【问题标题】:No implicit reference conversion between derived interfaces派生接口之间没有隐式引用转换
【发布时间】:2021-06-08 14:24:54
【问题描述】:

目标

构造一个实现ICoolbag 的具体对象,并且只能存储ICoolBagGrocery 而不是任何类型的带有IGrocery 的杂货店。

问题

下面的实现导致如下错误:

The type 'SolidDistribution.Core.Bag.CoolBag.ICoolBag' cannot be used as type parameter 'T' 
in the generic type or method 'IBagStorage<T>'. There is no implicit reference conversion from
 'SolidDistribution.Core.Bag.CoolBag.ICoolBag' to 'SolidDistribution.Core.Bag.IBag<SolidDistribution.Core.IGrocery>'.

实施

// A bag that can only hold coolbag groceries.
public interface ICoolBag : IBag<ICoolBagGrocery> { }

// a bag that can hold any type of grocery.
public interface IBag<T> : IGroceryStorage<T> where T : IGrocery { }

存储

// A storage that can store any type of grocery.
public interface IGroceryStorage<T> : IStorage<T> where T : IGrocery { }

// A storage that can store any type of bag.
public interface IBagStorage<T> : IStorage<T> where T : IBag<IGrocery> { }

// Base storage interface.
public interface IStorage<T> { }

杂货店

// A grocery that can only be stored in a coolbag.
public interface ICoolBagGrocery : IGrocery { }

// Base grocery interface.
public interface IGrocery { }

盒子

// A box with a bag that can only hold coolbag groceries.
public interface ICoolBox : IBoxWithBag<ICoolBag> { }

// Base box with bag storage interface.
public interface IBoxWithBag<T> : IBox, IBagStorage<T> where T : IBag<IGrocery> { }

// Base box interface.
public interface IBox { }

注意

ICoolbag 更改为使用IGrocery 而不是ICoolBagGrocery,如下所示: (public interface ICoolBag : IBag&lt;IGrocery&gt; { }) 修复了错误,但同时能够将任何类型的杂货放入冷藏袋中。这显然不应该发生:)

【问题讨论】:

标签: c# interface implicit-conversion derived-class


【解决方案1】:

您的编译错误是因为TIBag&lt;T&gt; 中是不变的。

ICoolBag 是一个IBag&lt;ICoolBagGrocery&gt;,但IBag&lt;ICoolBagGrocery&gt; 不是一个IBag&lt;IGrocery&gt;

如果您要在IBag&lt;T&gt; 中创建T 协变(使用out),那么IBag&lt;ICoolBagGrocery&gt; 将是IBag&lt;IGrocery&gt;

public interface IBag<out T> : IGroceryStorage<T> where T : IGrocery { }

但是,这会对您的 IBag&lt;T&gt; 接口施加限制:T 类型的属性不允许使用 set,并且方法只能使用 T 作为返回类型,而不是参数类型。

例如:

public interface IBag<out T> : IGroceryStorage<T> where T : IGrocery
{
    T SomeProperty { get; } // Allowed
    T AnotherProperty { get; set; } // Compilation error

    T SomeMethod(); // Allowed
    void AnotherMethod(T t); // Compilation error
}

此外,方差会随着继承层次的增加而上升,这意味着T 还需要在IGroceryStorage&lt;T&gt;IStrorage&lt;T&gt; 中是协变的才能使其有效。

【讨论】:

  • 感谢您的回答,我会进一步研究这个主题,因为它还没有完全落地。
  • 是的,这不是很明显。差异为何重要的一个简单示例:List&lt;Fruit&gt; fruits = new List&lt;Apple&gt;(); fruits.Add(new Banana());。显然这是不允许的,这也是编译器强制执行它的原因。
  • 是的,我明白这一点。我现在正在进一步研究 in out 关键字以及它如何触发不同的差异:) 谢谢
  • 当我在IBag&lt;T&gt; 中指定T 是协变的(使用out),然后在IGroceryStorage 中使T 逆变,并在IStorage 中使T 逆变(使用in) 我得到以下错误:Invalid variance: The type parameter 'T' must be contravariantly valid on 'IGroceryStorage&lt;T&gt;'. 'T' is covariant.
  • 抱歉,应该是协变的。每个接口都需要out 修饰符。
猜你喜欢
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
相关资源
最近更新 更多