具有泛型参数的类型和操作的字典

时间:2018-04-13 00:39:09

标签: c# generics delegates action

我正在尝试使用MessagePack获取简单的消息传递服务。

该服务应保留DateFormat,以便查找如何处理"交易"带有特定信息。

基本上,我有:

dictionary<type, Action<T>>

我明白了:

    private Dictionary<Type, Action<IMessage>> subActions;

    public void Subscribe<TMessage>(Action<TMessage> action) where TMessage : IMessage
    {
        subActions.Add(typeof(TMessage), action);
    }

如果不清楚;消息&#34;到达&#34;作为Argument 2: cannot convert from 'System.Action<TMessage>' to 'System.Action<GameServer.Messages.IMessage>' 包含&#34;类型代码&#34;。来自&#34; typecode&#34;我得到了byte[],而然后能够查找相应的Type。显然,Action应该将Action作为参数。

我似乎无法得出逻辑结论,为什么编译器会给我这个错误,尽管我怀疑它与TMessageDictionary不在同一个上下文中有关。 1}}。

提前致谢!

2 个答案:

答案 0 :(得分:0)

让我们考虑一下这些方法:

public void MessageMethodInterface(IMessage arg)
{

}
public void MessageMethodClass(MyMessage arg)
{

}

其中MyMessage是实现IMessage接口的类。

现在让我们创建一个Action并使用它们:

var action = new Action<IMessage>(MessageMethodInterface);
action(new SomeOtherMessage());

SomeOtherMessage实施IMessage。这会奏效。我们有ActionIMessage作为输入。由于SomeOtherMessage实现了IMessage,因此它可以编译并运行。

现在让我们创建另一个Action

var action2 = new Action<IMessage>(MessageMethodClass);
action(new SomeOtherMessage());

这不起作用:我们创建了一个Action,它应该接受IMessage类型的任何对象,但是我们为它分配了一个只能处理类型为MyMessage类的输入的方法 - 因此我们用我们提供的方法缩小了行动的范围 - 它不会编译。

代码中发生的情况是方案2.您希望字典包含可以处理IMessage的方法,但是您传递的方法只能处理特定类型。这不是类型安全的。即使一个类实现了接口,该方法本身也只处理特定类型,而不是该接口的每种类型。与使用MyMessageSomeOtherMessage的示例相同。

这是Action类型的逆转。
基类型的Action可以分配派生类型的操作。这是类型安全的b / c只使用基类型的方法将知道如何处理派生类型。反之则不然。以object作为输入的方法将处理string。由于string公开了object的所有方法和属性。但不是相反。

更多关于contravariance of Action type is here

答案 1 :(得分:0)

它不起作用,因为您想要进行如下分配:

Action<IMessage> dest = new Action<TMessage>(x => x.TMessageProp = 123);

所以,如果编译器允许它,你可以进一步编写:

dest(new TAnotherMessage());

因为TAnotherMessage也实现了IMessage。但它会导致异常,因为dest只适用于TMessage。阅读有关逆变的更多信息。

您可以保持类型安全和fix it safely,因为您知道类型,您可以通过字典键传递给特定操作:

public void Subscribe<TMessage>(Action<TMessage> action) where TMessage : IMessage
{
    subActions.Add(typeof(TMessage), x => action((TMessage)x));
}