这个问题涉及事件(基类事件和子类事件)和事件处理程序。我正在研究现有的代码,这似乎并不像作者所期望的那样有效。我很难理解为什么它不起作用,所以我想了解发生了什么,然后我试图修复现有的代码。
我发现了以下问题,这可能意味着我需要为子类型事件创建一个额外的事件处理程序,也可能不需要:
C#: Raising an inherited event
如果做一个额外的事件处理程序确实是解决方案,我仍然想知道为什么会这样。这是我在这里的第一个问题,我确实试图寻找我的问题的答案/解释,但如果这仍然是我应该很容易找到的东西,我真诚地道歉。严厉的“rtfm!”在这一点上,与教育联系对我来说没关系:)
我们有两个事件类,一个基类型和一个子类型。存在子类型事件以处理删除事件。
public class BaseTypeEvent
{
public Guid Id { get; set; }
public string Name { get; set; }
public BaseTypeEvent()
{ }
public BaseTypeEvent(SomeRandomThing item)
{
Id = item.Id;
Name = item.Name;
}
}
public class SubTypeEvent : BaseTypeEvent
{
public DateTimeOffset Deleted { get; set; }
public SubTypeEvent()
{
Deleted = DateTimeOffset.UtcNow;
}
}
使用这些似乎失败的事件:
public class UsageClass
{
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyBaseTypeEvents += HandleMethod;
}
private void HandleMethod(BaseTypeEvent e)
{
if(e is SubTypeEvent)
{
//code that deals with deletion events
//execution never actually gets here
}
//code that deals with events that are not deletion events
}
}
事件的声明位于ieventbusservice和eventbusservice中:
public delegate void MyEventHandler(BaseTypeEvent e);
public interface IEventBusService
{
public event MyEventHandler MyBaseTypeEvents;
void PublishStuff(BaseTypeEvent e);
}
public class EventBusService : IEventBusService, IDisposable
{
public void Initialize()
{
//Bus is MassTransit
Bus.Initialize(sbc =>
{
sbc.Subscribe(subs => subs.Handler<BaseTypeEvent>(OnBaseTypeEvent));
}
}
private void OnBaseTypeEvent(BaseTypeEvent e)
{
if (MyBaseTypeEvents == null) return;
try
{
MyBaseTypeEvents(e);
}
catch (Exception e)
{
//some logging
}
}
public event MyEventHandler MyBaseTypeEvents;
public void PublishStuff(BaseTypeEvent e)
{
//some logging
//publish e to the event bus of our choice (MassTransit)
Bus.Instance.Publish(e);
}
}
最后是我们发送删除事件的地方(尝试删除上面我巧妙命名的某个随机事件的一项):
eventBusService.PublishStuff(new SubTypeEvent
{
Id = id,
Deleted = DateTimeOffset.UtcNow
});
所以问题是:在用上面最后一行代码发送删除事件之后,usageclass中用于检查传入事件是否属于subtype event类型的if语句实际上永远不是真的。UsageClass的handleMethod中e的类型是baseTypeEvent。
编辑:
在这种情况下,我已经决定去掉这种类型。我们现在不再有basetypeevent和subtype event,而只是eventtypea和eventtypeb。一个处理创建和更新,另一个处理删除(我们需要的创建和更新的信息要少得多)。
public delegate void MyEventAHandler(EventTypeA e);
public delegate void MyEventBHandler(EventTypeB e);
和
void PublishStuffForA(EventTypeA e);
void PublishStuffForB(EventTypeB e);
等等。
我在eventbusservice的initialize方法中额外订阅了mastransit,并在各种需要它们的usageclasses中创建了额外的处理程序:
sbc.Subscribe(subs => subs.Handler<EventTypeA>(OnEventTypeA));
sbc.Subscribe(subs => subs.Handler<EventTypeB>(OnEventTypeB));
和
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyEventTypeAEvents += HandleMethodForA;
eventBusService.MyEventTypeBEvents += HandleMethodForB;
}
等等。
我现在不再需要检查传入的事件是否属于某一类型,只需分别处理两种类型。也许是个逃避,但确实有效。
我很犹豫是否把这个定义为我自己问题的答案,因为@glubus'的评论和@travis'的评论是我问题的答案。我还是觉得这篇小的编辑文章能让大家知道我的解决方案:)
编辑2:
有帮助的信息来源:
Derived types are not published to consumers in MassTransit
MassTransit message mis-typing
MassTransit: Message contracts, polymorphism and dynamic proxy objects
https://groups.google.com/forum/#!searchin/masstransit-discuss/polymorphism/masstransit-discuss/q_M4erHQ7OI/FxaotfIzI7YJ
最佳答案
所以我可以告诉你一个简短的答案:
在消息传递契约中使用多态性会引入耦合。
我们相信,作为大众运输开发商,这是一个坏主意。这仍然是可能的,但不是现成的。您必须使用二进制序列化或客户序列化程序。默认情况下,序列化管道仅在使用者中填充该类型的代理。