C#协方差和协方差

时间:2018-08-10 19:40:03

标签: c# generics covariance 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());
    }
}

我有一个例外:

  

无法将Bar转换为IFoo<Message,Message>

  

无法将Baz转换为IFoo<Message,Message>

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

2 个答案:

答案 0 :(得分:4)

  

如何将Bar和Baz实例添加到列表中?

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

答案 1 :(得分: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
            // ...
        }
    }

IFoo<Message2D, Message>实现Baz

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