C# 协变和逆变

C# Covariance and Contravariance

我有 类 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());
    }
}

我有一个例外:

Can not convert Bar to IFoo<Message,Message>

Can not convert Baz to IFoo<Message,Message>

如何将 BarBaz 个实例添加到列表中?

How can I add Bar and Baz instances to the List?

你不能,因为你试图将输入消息视为协变的,但它是逆变的。您可以将 IFoo<Message1D, Message> 视为 IFoo<Message, Message>,但不能将 IFoo<Message, Message1D> 视为 IFoo<Message, Message>。如果那是有效的,那么将允许某人将 2D 消息传递到只能处理 1D 消息的对象中。

正如@Servy 所提到的,在您当前的体系结构中这是不可能的,您可能应该重新制作它。

但是如果你能以某种方式保证类型安全,那么除了 IFoo<Message1D, Message1D> 之外,你还可以尝试显式实现 IFoo<Message1D, Message>,如下所示:

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>

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