【问题标题】:Using dynamic keyword and calling generic method in base class results in StackOverflowException在基类中使用动态关键字并调用泛型方法会导致 StackOverflowException
【发布时间】:2012-12-05 15:21:12
【问题描述】:

根据我的question(泛型方法的可重用非泛型方法),我已经实现了提供的解决方案,但是经过一些重构(将代码移动到基类)我的代码导致了我不明白的 StackOverflowException。

Handle(new TestCommand()) 的调用导致IMessageHandler.Handle(IMessage) 被调用,然后Handle<TMessage>(TMessage) 被调用,但不是调用继承类的Handle(TestCommand message),而是再次调用IMessageHandler.Handle(IMessage)

泛型方法中IMessageHandler<TestCommand> 的 as-cast 有效,否则它将调用 HandleUnknownMessage(IMessage)

这很难描述,所以这里是我的测试代码:

class Program {
    static void Main(string[] args) {

        MyProcess p = new MyProcess();
        IMessageHandler handler = p;

        handler.Handle(new DummyCommand()); // works -> HandleUnknownMessage gets called as expected

        handler.Handle(new TestCommand());  // fails -> results in a StackOverflowException 
    }
}  

public abstract class ProcessBase : IMessageHandler {
    void IMessageHandler.Handle(IMessage message) {
        System.Diagnostics.Debug.WriteLine("Dynamic Message gets handled");
        dynamic dynamicMessage = message;

        Handle(dynamicMessage);
    }

    private void Handle<TMessage>(TMessage message) where TMessage : IMessage {
        System.Diagnostics.Debug.WriteLine("Generic Message gets handled");
        var handler = this as IMessageHandler<TMessage>;
        if (handler == null)
            HandleUnknownMessage(message);
        else
            handler.Handle(message);
    }

    protected virtual void HandleUnknownMessage(IMessage unknownMessage) {
        System.Diagnostics.Debug.WriteLine("Unknown message {0} passed to Process".FormatWith(unknownMessage.GetType()));
        // Handle unknown message types here.
    }
}

public class MyProcess : ProcessBase, IMessageHandler<TestCommand>, IMessageHandler<TestEvent> {

    public void Handle(TestCommand commandMessage) {
        System.Diagnostics.Debug.WriteLine("TestCommand gets handled");
    }

    public void Handle(TestEvent eventMessage) {
        System.Diagnostics.Debug.WriteLine("TestEvent gets handled");
    }
}

public class DummyCommand : IMessage {    }

public class TestCommand : IMessage {    }

如果我将基类ProcessBase 中的代码放到MyProcess 中,代码可以正常工作。将动态关键字与泛型方法和继承结合使用是否有任何限制?

【问题讨论】:

  • IMessageHandler&lt;T&gt; 是否定义了 Handle&lt;T&gt;(T) 方法?编辑:你能发布IMessageHandlerIMessageHandler&lt;T&gt;吗?
  • @Chris Sinclair:该死的,你是对的。我错过了在 IMessageHandler 上定义 Handle
  • 没问题。我将不得不记住这种技术;这是一种将运行时调用提升为编译时通用调用的聪明方法。 (我建议在 ProcessBase 上重命名私有 Handle&lt;TMessage&gt; 方法,以避免在方法解析上出现问题)

标签: c# generics inheritance dynamic .net-4.0


【解决方案1】:

尝试在IMessageHandler&lt;TMessage&gt; 上定义void Handle&lt;TMessage&gt;(TMessage message) 方法。

由于未定义,您定义的MyProcess.Handle 事件属于该类,而不属于它实现的接口。当您的代码尝试调用您的IMessageHandler&lt;TMessage&gt; handler 时,它不知道它实际上是具有这些特定方法的MyProcess。添加接口方法后,调用解析应该识别出这些方法存在于MyProcess 上并调用它们。否则它只会调用下一个最佳方法IMessageHandler.Handle(IMessage),这会产生无限循环。

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2017-03-03
    相关资源
    最近更新 更多