C# 协变和逆变
C# Covariance and Contravariance
我有 类 Message1D
和 Message2D
都继承自 Message
:
public abstract class Message {}
public class Message1D : Message {}
public class Message2D : Message {}
实现它的接口IFoo
和类Bar
和Baz
:
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>
如何将 Bar
和 Baz
个实例添加到列表中?
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>
。
这将使您的代码正常工作,但这很可能不是您的最佳决定。
我有 类 Message1D
和 Message2D
都继承自 Message
:
public abstract class Message {}
public class Message1D : Message {}
public class Message2D : Message {}
实现它的接口IFoo
和类Bar
和Baz
:
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
toIFoo<Message,Message>
和
Can not convert
Baz
toIFoo<Message,Message>
如何将 Bar
和 Baz
个实例添加到列表中?
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>
。
这将使您的代码正常工作,但这很可能不是您的最佳决定。