无法转换协变通用接口

Unable to cast covariant generic interfaces

我有两个接口:

public interface ISnack { }

public interface IWrapper<TSnack> where TSnack : ISnack
{
   void Wrap(TSnack snack);
}

还有两个类:

public class CheeseCakeContainer : IWrapper<CheeseCake>
{
    CheeseCake c;
    public void Wrap(CheeseCake snack)
    {
        c = snack;
    }
}

public class CheeseCake : ISnack { }

我要执行

IWrapper<ISnack> wrappedSnack = (IWrapper<ISnack>)(new CheeseCakeContainer());
var c1 = new CheeseCake();
wrappedSnack.Wrap(c1);

但这会抛出一个无效的转换异常

System.InvalidCastException: 'Unable to cast object of type 'CheeseCakeContainer' to type 'IWrapper`1[ISnack]'.'

我应该更改什么才能使转换工作?我正在使用 C#9 和 .NET5

问题的症结在于您正在尝试创建一个 协变 的容器,或者您正在将更派生的类型分配给更通用的类型(CheeseCakeISnack) 同时尝试调用应该是 逆变 的接口方法,或者实现更派生的类型 (CheeseCake)。这种类型的双向变化在 C# 中是非法的。

因此,您基本上有两个选择。您可以在容器创建期间放弃协变,这允许您在实现中保持逆变,或者您可以在容器创建期间使用协变,但您将被迫在实现中强制转换为目标类型以满足接口。

前者具有逆变IWrapper<in TSnack>定义:

CheeseCakeContainer wrappedSnack = new CheeseCakeContainer();
var c1 = new CheeseCake();
wrappedSnack.Wrap(c1);


public interface ISnack { }
public interface IWrapper<in TSnack> where TSnack : ISnack
{
    void Wrap(TSnack snack);
}

public class CheeseCakeContainer : IWrapper<CheeseCake>
{
    public void Wrap(CheeseCake snack)
    {
        snack.Type = "Strawberry";
    }
}

public class CheeseCake : ISnack 
{ 
    public string Type { get; set; }    
}

后者:

IWrapper<ISnack> wrappedSnack = new CheeseCakeContainer();
var c1 = new CheeseCake();
wrappedSnack.Wrap(c1);

public interface ISnack { }
public interface IWrapper<out TSnack> where TSnack : ISnack
{
    void Wrap(ISnack snack);
}

public class CheeseCakeContainer : IWrapper<CheeseCake>
{
    public void Wrap(ISnack snack)
    {
        ((CheeseCake)snack).Type = "Strawberry";
    }
}

public class CheeseCake : ISnack
{
    public string Type { get; set; }
}