无法强制转换协变泛型接口



我有两个接口:

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:'无法强制转换类型为的对象"CheeseCakeContainer"类型为"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; }
}

最新更新