Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在C#中实现高效的pubsub时,泛型强制转换问题,在提交子类型消息时调用侦听器_Java_C#_Publish Subscribe - Fatal编程技术网

Java 在C#中实现高效的pubsub时,泛型强制转换问题,在提交子类型消息时调用侦听器

Java 在C#中实现高效的pubsub时,泛型强制转换问题,在提交子类型消息时调用侦听器,java,c#,publish-subscribe,Java,C#,Publish Subscribe,我试图用C#实现一个高效的pubsub模块。要求很简单:订阅/取消订阅时没有太多的性能要求,但发布时必须尽可能地提高性能 简而言之,我使用容器类(节点)来包含特定类型上的所有侦听器,当发布消息时,将调用完全相同消息类型上的所有侦听器 重要的是,除了这个基本功能外,我还想通知消息超类上的订阅者(例如,当发布苹果时,应该通知Fruit类上的订阅者)。为此,Node类需要包含满足其超类型的其他节点。订阅/取消订阅时将维护该图。发布消息时,将递归调用所有超级类型节点 下面的尝试是我的Java实现中的一个

我试图用C#实现一个高效的pubsub模块。要求很简单:订阅/取消订阅时没有太多的性能要求,但发布时必须尽可能地提高性能

简而言之,我使用容器类(节点)来包含特定类型上的所有侦听器,当发布消息时,将调用完全相同消息类型上的所有侦听器

重要的是,除了这个基本功能外,我还想通知消息超类上的订阅者(例如,当发布苹果时,应该通知Fruit类上的订阅者)。为此,Node类需要包含满足其超类型的其他节点。订阅/取消订阅时将维护该图。发布消息时,将递归调用所有超级类型节点

下面的尝试是我的Java实现中的一个端口。我在设计中遇到的问题是关于泛型类型转换


公共代表无效消费者(X obj);
公共类PubSubImpl:PubSub
{
专用只读字典节点;
公共PubSubImpl()
{
节点=新字典();
}
公共int调用(T obj)
{
Node Node=nodes.GetOrDefault(obj.GetType(),CreateNode);
返回node.Invoke(obj);
}
专用节点CreateNode(类型)
{
节点=新节点();
foreach(节点中的var条目)
{
//如果新类型是此节点的子类型
if(entry.Key.IsAssignableFrom(type))
{
node.superTypes.Add(entry.Value);
}
if(type.IsAssignableFrom(entry.Key))
{
entry.Value.superTypes.Add(节点);
}
}
添加(类型,节点);
返回节点;
}
public void Subscribe(对象订阅者、使用者操作)
{
类型=类型(T);
Node Node=nodes.GetOrDefault(类型,CreateNode);
添加(新处理程序(订阅者,操作));
Log(“现在处理程序:“+type+”“+node.Handlers.Count”);
}
公共无效取消订阅(对象订户,消费者行动)
{
类型=类型(T);
Node Node=nodes.GetOrDefault(类型,CreateNode);
node.handlers.removehere(h=>h.subscriber==subscriber&&h.action==action);
}
public void UnsubscribeAll(对象订户)
{
foreach(nodes.Values中的节点n)
{
n、 handlers.RemoveWhere(h=>h.subscriber==subscriber);
}
}
内部类节点
{
公共只读哈希集超类型;
公共只读哈希集处理程序;
公共节点()
{
superTypes=newhashset();
handlers=newhashset();
}
公共int调用(T有效负载)
{
int res=0;
foreach(处理程序中的处理程序)
{
Log(handler.action.GetType());
/****************************************************************
注意:这就是我射中自己脚的地方。
在Java中,类型擦除允许我做一些疯狂的事情,只要我保证维护内部结构。
在C#中,我们有强类型,这里似乎不能同时有协方差和反方差。
****************************************************************/
((消费者)处理器动作)(有效载荷);
res++;
}
foreach(超类型中的节点)
{
res+=node.Invoke(有效负载);
}
返回res;
}
}
内部类处理程序
{
公共只读对象订阅者;
公共只读委托操作;
公共处理程序(对象订户、委托操作)
{
this.subscriber=subscriber;
这个动作=动作;
}
}
}
如果有人能告诉我如何在C#中实现这一点,我将不胜感激,任何解决方法,甚至是对替代数据结构的建议都将不胜感激

编辑

发现根本原因是网络版本(Unity3D默认使用.NET 3.5…duh)。在升级.NET版本后,演员阵容非常出色!例如,在4.x中工作但不是在3.5中工作的铸件如下所示

Consumer=(f)=>{};
消费者苹果=(消费者)水果消费者;

也许我看错了,但我看不出您从超级类型列表中删除了哪些已取消订阅的邮件类型。这种消息类型不应该被完全删除吗?@selalerer不知道你在这里的意思。假设我们有苹果->树柚子->水果层次结构,并且我正在订阅苹果,那么如果我取消订阅,我将只需要触摸苹果节点。Treefuit和Fruit节点上的订户根本不需要触摸。如果您将订户注册到Fruit,它也会在Apple的超类型中注册。当您注销此订阅服务器时,它只会从水果中删除,而不会从苹果的superTypes@selalerer我明白你的意思。我认为这是一个不太重要的话题,需要听取意见。您可能会认为离开一个悬空节点会不必要地旋转CPU,我可能会认为,因为我有非常频繁的sub/unsub,所以我可能希望将该节点保留在那里,而不是继续删除/重新实例化它。你能帮我解决这个问题吗?如果有帮助的话,也许你可以忽略我的所有代码,除了合同(sub、unsub、invoke),然后尝试实现它。你可以让你的
消费者
成为一个
界面
,而不是一个
委托
,并为其提供一个方法
消费(对象obj)
,然后你的订阅者只需要一个对象。在我看来,在Java中,你也没有真正的类型安全。也许我读错了,但我没有