C#中的协变性和逆变性

3
我有两个类 Message1DMessage2D,它们都继承自 Message 类:
public abstract class Message {}
public class Message1D : Message {}
public class Message2D : Message {}

一个接口IFoo和实现它的类BarBaz:
public interface IFoo<out G, in T> 
    where G : Message 
    where T : Message
{
    G PassMessage(T input);
}

public class Bar : IFoo<Message1D, Message1D>
{
    public Message1D PassMessage(Message1D input)
    {
        throw new NotImplementedException();
    }
}

public class Baz : IFoo<Message2D, Message2D>
{
    public Message2D PassMessage(Message2D input)
    {
        throw new NotImplementedException();
    }
}

我的问题在这里。我如何将Foo和Bar实例添加到列表中?

public class Network
{
    private List<IFoo<Message, Message>> messages = new List<IFoo<Message, Message>>();

    public void AddBar()
    {
        messages.Add(new Bar());
    }

    public void AddBaz()
    {
        messages.Add(new Baz());
    }
}

我遇到了一个异常:

不能将类型为Bar的对象转换为类型IFoo<Message,Message>

以及

不能将类型为Baz的对象转换为类型IFoo<Message,Message>

我该如何将BarBaz实例添加到List中?

2个回答

4
我如何将Bar和Baz实例添加到列表中?
你不能这样做,因为您试图将输入消息视为协变,但它是反变的。您可以将一个IFoo<Message1D, Message>视为IFoo<Message,Message>,但您不能将IFoo<Message,Message1D>视为IFoo<Message,Message>。如果允许这样做,那么某些人将能够将2D消息传递给只能处理1D消息的对象。

美好!感谢您先生! - koryakinp

0

正如@Servy所提到的,根据你目前的架构,这是不可能实现的,你可能需要重新设计。

但是如果你能够保证类型安全,那么你可以尝试显式地实现IFoo<Message1D, Message>,并将其添加到IFoo<Message1D, Message1D>中,如下所示:

public class Bar : IFoo<Message1D, Message1D>, IFoo<Message1D, Message>
{
    public Message1D PassMessage(Message1D input)
    {
        // ...
    }

    Message1D IFoo<Message1D, Message>.PassMessage(Message input)
    {
        try
        {
            return PassMessage((Message1D) input);
        }
        catch (InvalidCastException)
        {
            // Message2D passed, handling exception
            // ...
        }
    }

同样地,为 Baz 实现 IFoo<Message2D, Message>

这将使您的代码工作,但很可能不是最好的决定。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接