派生接口之间没有隐式引用转换

No implicit reference conversion between derived interfaces

目标

构建一个实现 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<IGrocery> { }) 修复了错误,但同时启用了将任何类型的杂货放入冷藏袋的能力。这显然不应该发生:)

你的编译错误是因为TIBag<T>中是不变的。

ICoolBag 是一个 IBag<ICoolBagGrocery>,但是 IBag<ICoolBagGrocery> 不是 一个 IBag<IGrocery>.

如果要在 IBag<T> 中使 T 协变 (使用 out),那么 IBag<ICoolBagGrocery> 将是IBag<IGrocery>:

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

但是,这会对您的 IBag<T> 接口施加限制:T 类型的属性不允许 set,并且方法只能使用 T 作为 return类型,不是参数类型。

例如:

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<T>IStrorage<T> 中是协变的才能使其有效。