C#中派发到派生类的动态分派

9
我将尝试完成以下操作:
public abstract BaseClass {

  public virtual void ReceiveEvent(Event evt)
    {
        ProcessEvent(evt as dynamic);
    }

    private void ProcessEvent(object evt)
    { 
        LogManager.Log(@"Received an event that is not being processed! 
                        Dispatch fallback");
    }
}

public DerivedClass: BaseClass {

    private void ProcessEvent(SpecificEvent evt)
    { 
        LogManager.Log("Processing Event");
    }
}

特定事件应该使用派生类中的方法而不是回退方法。我一直在同一个类中使用动态分派,发现这非常有用/干净。就像上面的示例中所示,它不能与派生类一起使用吗?
编辑: 答案似乎存在一些混淆。基本上,我一直使用以下设计:
public class SomeClass{

    public void DoSomethingDispatcher(SomeObject obj)
    {
        ProcessObject(obj as dynamic);
    }

    private void DoSomething(SomeObjectType1 obj)
    { 

    }

    private void DoSomething(SomeObjectType2 obj)
    { 

    }

    private void DoSomething(SomeObjectType3 obj)
    { 

    }

    private void DoSomething(object obj) //fallback
    { 

    }
}

你不知道具体类型,又不想使用庞大的switch语句时,这种方法非常有效。我想知道是否可以使用继承来实现,其中基类保存回退方法,派生类保存所有更具体的方法。


我的猜测是ReceiveEvent被调用在BaseClass上而不是DerivedClass上。你尝试过在DerivedClass上重写ReceiveEvent吗?它是虚拟的,所以你可以这样做:public override void ReceiveEvent(Event evt)。这里有更多关于虚方法的信息:http://msdn.microsoft.com/en-us/library/aa645767%28v=vs.71%29.aspx - Davio
4个回答

6
你无法正常工作的原因是,即使evt是动态传递的,ProcessEvent没有被声明为虚拟方法。这意味着当编译对 ProcessEvent 的调用时,它会链接到在基类中找到的唯一方法实现,并且派生类中的方法永远不会被执行。此外,你不能简单地将 ProcessEvent 声明为虚拟方法,因为派生类中的签名将有所不同。
为了让你的代码按预期工作,你可以在派生类中重写 ReceiveEvent 方法,使其完全相同:
  public override void ReceiveEvent(Event evt)
    {
        ProcessEvent(evt as dynamic);
    }

如果你想在基类中管理未处理的事件,只需将基类中 Process 事件的修饰符更改为 protected(否则当被 ReceiveEvents 的重写版本调用时,它无法执行)。


是的,这就是我现在写的方式。猜想这是最接近的解决方案了。我本来希望能将回退移动到基类中,但根据你描述的编译过程似乎不可能。谢谢。 - Jamona Mican
哦,我刚注意到最后一段。我会尝试一下! - Jamona Mican

2

如果基类中的方法不是 virtual/abstract,并且在派生类中该方法没有被标记为 override,那么它永远不会起作用。

此外,我不理解这里使用 dynamic 的用法。


1
动态在这里被用作一种很好的方式,将未知的对象类型路由到它们适当的处理程序,而不使用 switch 语句。 - Jamona Mican

0
为了获得预期的行为,您应该重写虚拟方法:
public DerivedClass: BaseClass
{
  private override void ReceiveEvent(Event evt)
  { 
      // Process your event here.
  }
}

通过这段代码,基类中的ReceiveEvent不会被调用,因此回退的ProcessEvent也不会被调用。
没有使用dynamic的理由。

0

当 "evt" 触发 ProcessEvent 时,它的类型是什么?

您可以查看 使用动态类型

该类型是静态类型,但类型为 dynamic 的对象绕过了静态类型检查。在大多数情况下,它的功能类似于具有类型 object。

因此,evt 不是 SpecificEvent


首先,动态将被视为对象。 然后,您的继承似乎不正确,方法中没有“virtual”/“abstract”/“override”甚至“new”。 您可以尝试在BaseClass的ProcessEvent方法上放置virtual,并在DerivedClass上覆盖。 - kerrubin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接