C# 泛型方法的可重用非泛型方法

C# 泛型方法的可重用非泛型方法,c#,generics,interface,C#,Generics,Interface,我有以下基本接口 public interface IHandler{ void Handle(IMessage message); } public interface IHandler<TMessage> : IHandler where TMessage : IMessage{ void Handle(TMessage message); } 以及继承基本接口的通用接口 public interface IHandler{ void Handle(IMessag

我有以下基本接口

public interface IHandler{
  void Handle(IMessage message);
}
public interface IHandler<TMessage> : IHandler where TMessage : IMessage{
  void Handle(TMessage message);
}
以及继承基本接口的通用接口

public interface IHandler{
  void Handle(IMessage message);
}
public interface IHandler<TMessage> : IHandler where TMessage : IMessage{
  void Handle(TMessage message);
}
困扰我的是我必须实现
Handle(IMessage)
方法的方式,因为在我看来它有很多冗余代码,每次在类上实现新的
IHandler
接口时,我都必须扩展该方法


我正在寻找一种更通用的方法来实现
Handle(IMessage)
方法(可能是在处理程序的基类中),但我目前一直在思考如何实现它。

合理的方法是明智地使用反射:

var method = this.GetType().GetMethod("Handle", new[] { message.GetType() });

if (method != null) {
    method.Invoke(this, new[] { message });
}

如果您这样做太多以至于性能出现问题,您可以缓存测试结果以获得巨大的改进。

合理的方法是明智地使用反射:

var method = this.GetType().GetMethod("Handle", new[] { message.GetType() });

if (method != null) {
    method.Invoke(this, new[] { message });
}

如果您这样做太多以至于性能出现问题,您可以缓存测试结果以获得巨大改进。

您可以使用新的
动态
关键字将过载分辨率移动到DLR:

void IHandler.Handle(IMessage message)
{
    dynamic d = message;
    Handle(d);
}
请注意,如果传入的消息对您的类无效,此操作将在运行时失败,并出现
RuntimeBinderException

要避免此异常,可以为所有未知消息类型添加处理程序:

private void Handle(object unknownMessage)
{
    // Handle unknown message types here.
}

要在基类中实现
IHandler.Handle
,您需要做更多的工作:

public class BaseHandler : IHandler
{
    void IHandler.Handle(IMessage message)
    {
        dynamic d = message;
        Handle(d);
    }

    private void Handle<TMessage>(TMessage message) where TMessage : IMessage
    {
        var handler = this as IHandler<TMessage>;
        if(handler == null)
            HandleUnknownMessage(message);
        else
            handler.Handle(message);
    }

    protected virtual void HandleUnknownMessage(IMessage unknownMessage)
    {
        // Handle unknown message types here.
    }
}
公共类BaseHandler:IHandler
{
void IHandler.Handle(IMessage消息)
{
动态d=消息;
手柄(d);
}
私有无效句柄(TMessage message),其中TMessage:IMessage
{
var handler=此为IHandler;
if(handler==null)
Handleunknown消息(消息);
其他的
handler.Handle(消息);
}
受保护的虚拟无效HandleUnknownMessage(IMessage unknownMessage)
{
//在此处处理未知的消息类型。
}
}
您的特定处理程序将如下所示:

public class ExampleHandler : BaseHandler,
                              IHandler<ExampleMessage>,
                              IHandler<OtherExampleMessage>
{
    public void Handle(ExampleMessage message)
    {
        // handle ExampleMessage here
    }

    public void Handle(OtherExampleMessage message)
    {
        // handle OtherExampleMessage here
    }
}
公共类ExampleHandler:BaseHandler,
伊汉德勒,
伊汉德勒
{
公共无效句柄(例如消息)
{
//在这里处理示例消息
}
公共无效句柄(其他示例消息)
{
//在此处处理其他示例消息
}
}
此代码现在的工作方式如下:

public class ExampleHandler : BaseHandler,
                              IHandler<ExampleMessage>,
                              IHandler<OtherExampleMessage>
{
    public void Handle(ExampleMessage message)
    {
        // handle ExampleMessage here
    }

    public void Handle(OtherExampleMessage message)
    {
        // handle OtherExampleMessage here
    }
}
  • DLR调用通用的
    BaseHandler.Handle
    方法和实际的消息类型,即
    TMessage
    将不是
    IMessage
    ,而是具体的消息类,如
    ExampleMessage
  • 在这个geneirc处理程序方法中,基类尝试将自己的大小写为特定消息的处理程序
  • 如果不成功,它将调用
    HandleUnknownMessage
    来处理未知的消息类型
  • 如果强制转换成功,它将调用特定消息处理程序上的
    Handle
    方法,有效地将调用委托给具体的处理程序实现

  • 您可以使用新的
    dynamic
    关键字将过载分辨率移动到DLR:

    void IHandler.Handle(IMessage message)
    {
        dynamic d = message;
        Handle(d);
    }
    
    请注意,如果传入的消息对您的类无效,此操作将在运行时失败,并出现
    RuntimeBinderException

    要避免此异常,可以为所有未知消息类型添加处理程序:

    private void Handle(object unknownMessage)
    {
        // Handle unknown message types here.
    }
    

    要在基类中实现
    IHandler.Handle
    ,您需要做更多的工作:

    public class BaseHandler : IHandler
    {
        void IHandler.Handle(IMessage message)
        {
            dynamic d = message;
            Handle(d);
        }
    
        private void Handle<TMessage>(TMessage message) where TMessage : IMessage
        {
            var handler = this as IHandler<TMessage>;
            if(handler == null)
                HandleUnknownMessage(message);
            else
                handler.Handle(message);
        }
    
        protected virtual void HandleUnknownMessage(IMessage unknownMessage)
        {
            // Handle unknown message types here.
        }
    }
    
    公共类BaseHandler:IHandler
    {
    void IHandler.Handle(IMessage消息)
    {
    动态d=消息;
    手柄(d);
    }
    私有无效句柄(TMessage message),其中TMessage:IMessage
    {
    var handler=此为IHandler;
    if(handler==null)
    Handleunknown消息(消息);
    其他的
    handler.Handle(消息);
    }
    受保护的虚拟无效HandleUnknownMessage(IMessage unknownMessage)
    {
    //在此处处理未知的消息类型。
    }
    }
    
    您的特定处理程序将如下所示:

    public class ExampleHandler : BaseHandler,
                                  IHandler<ExampleMessage>,
                                  IHandler<OtherExampleMessage>
    {
        public void Handle(ExampleMessage message)
        {
            // handle ExampleMessage here
        }
    
        public void Handle(OtherExampleMessage message)
        {
            // handle OtherExampleMessage here
        }
    }
    
    公共类ExampleHandler:BaseHandler,
    伊汉德勒,
    伊汉德勒
    {
    公共无效句柄(例如消息)
    {
    //在这里处理示例消息
    }
    公共无效句柄(其他示例消息)
    {
    //在此处处理其他示例消息
    }
    }
    
    此代码现在的工作方式如下:

    public class ExampleHandler : BaseHandler,
                                  IHandler<ExampleMessage>,
                                  IHandler<OtherExampleMessage>
    {
        public void Handle(ExampleMessage message)
        {
            // handle ExampleMessage here
        }
    
        public void Handle(OtherExampleMessage message)
        {
            // handle OtherExampleMessage here
        }
    }
    
  • DLR调用通用的
    BaseHandler.Handle
    方法和实际的消息类型,即
    TMessage
    将不是
    IMessage
    ,而是具体的消息类,如
    ExampleMessage
  • 在这个geneirc处理程序方法中,基类尝试将自己的大小写为特定消息的处理程序
  • 如果不成功,它将调用
    HandleUnknownMessage
    来处理未知的消息类型
  • 如果强制转换成功,它将调用特定消息处理程序上的
    Handle
    方法,有效地将调用委托给具体的处理程序实现

  • 你陷入困境是因为你的班级(在问题中)做了不止一件事。它处理
    ExampleMessage
    OtherExampleMessage
    。我建议您创建一个类来处理一件事

    示例:

    public class ExampleHandler : IHandler<ExampleMessage> 
    
    public类示例处理程序:IHandler
    

    public类OtherExampleHandler:IHandler
    

    根据我的理解,您希望有一个类来处理某种事件。在这种情况下,您可能必须使用通知每个处理程序什么时候发生了什么事情,并让他们做他们的工作。

    您卡住了,因为您的类(在问题中)做了不止一件事。它处理
    ExampleMessage
    OtherExampleMessage
    。我建议您创建一个类来处理一件事

    示例:

    public class ExampleHandler : IHandler<ExampleMessage> 
    
    public类示例处理程序:IHandler
    

    public类OtherExampleHandler:IHandler