简体   繁体   English

C#协方差和逆变

[英]C# Covariance and Contravariance

I have classes Message1D and Message2D both inherit from Message : 我有类Message1DMessage2D都继承自Message

public abstract class Message {}
public class Message1D : Message {}
public class Message2D : Message {}

An interface IFoo and classes Bar and Baz , which implement it: 实现它的接口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();
    }
}

And my problem is here. 我的问题在这里。 How can I add Foo and Bar instances to the list ? 如何将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());
    }
}

I have an exception: 我有一个例外:

Can not convert Bar to IFoo<Message,Message> 无法将Bar转换为IFoo<Message,Message>

and

Can not convert Baz to IFoo<Message,Message> 无法将Baz转换为IFoo<Message,Message>

How can I add Bar and Baz instances to the List ? 如何将BarBaz实例添加到列表中?

How can I add Bar and Baz instances to the List? 如何将Bar和Baz实例添加到列表中?

You can't, because you're trying to treat the input message as if it's covariant, but it's contravariant. 你不能,因为你试图将输入消息视为协变,但它是逆变的。 You can treat an IFoo<Message1D, Message> as an IFoo<Message, Message> , but you can't treat an IFoo<Message, Message1D> as an IFoo<Message, Message> . 您可以将IFoo<Message1D, Message>视为IFoo<Message, Message> ,但不能将IFoo<Message, Message1D>视为IFoo<Message, Message> If that were valid, then someone would be allowed to pass in 2D messages into your object that can only handle 1D messages. 如果这是有效的,那么将允许某人将2D消息传递到只能处理1D消息的对象中。

As @Servy mentioned, it is not possible in your current architecture and you should probably remake it. 正如@Servy所提到的,在您当前的架构中是不可能的,您应该重新制作它。

But if somehow you can guarantee type safety, then you can try to explicitly implement IFoo<Message1D, Message> in addition to IFoo<Message1D, Message1D> as follows: 但是如果你能保证类型安全,那么你可以尝试显式实现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
            // ...
        }
    }

Similarly implement IFoo<Message2D, Message> for Baz . 类似地为Baz实现IFoo<Message2D, Message>

That will make your code work, but it is most likely not the best decision for you. 这将使您的代码工作,但它很可能不是您的最佳决定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM