代码之家  ›  专栏  ›  技术社区  ›  OddBeck

如何从继承类型转换为运行时类型

  •  0
  • OddBeck  · 技术社区  · 6 年前

    在运行时处理正确的类型有问题。

    我希望我的代码根据参数类型动态地检测应该调用哪个处理程序。我不想将tevent强制转换为代码中的正确类型。

    所有处理程序都从我的接口继承:

    public interface IAbstractHandler < in T>  
    {
       void Handle(T evnt);
    }
    

    例子:

    public class SpecificEventHandler: IAbstractHandler< SpecificEvent>
    {
       public void Handle(SpecificEvent evnt) {
        ....
       }
    }
    

    Tecvent.cs公司:

    public class TEvent
    {
    }
    

    处理程序中使用的所有其他事件都来自tevent。

    下面是一些代码:

    List<TEvent> eventItems = new List<TEvent>();
    ....
    foreach (var evt in eventItems) {
      ...
      dynamic eventHandler = ResolveEventHandler(evt.GetType().Name);
      if (evt is MySubtypeEvent subEvent) {
        eventHandler.Handle(subEvent); // <-- this works, but I don't want this.
      }
      eventHandler.Handle(evt); // <-- And this fails, because 'evt' is seemingly 
      // a TEvent even though it's of the correct subclass.
    }
    

    我要寻找的是一种方法,使“evt”不是一个tevent,而是一个真正的类型,但如果不硬编码它,这将使我的“eventhandler.handle()”方法工作(我假设)。

    1 回复  |  直到 6 年前
        1
  •  1
  •   user2819245user2819245    6 年前

    通往罗马的路很多,解决问题的方法也不少。一种简单的方法是为具体的事件处理程序类型使用泛型抽象基类,它可以提供 Handle(TEvent evt) 方法。

    public abstract class HandlerBase<T> where T : TEvent, new()
    {
        public abstract void Handle(T evt);
    
    
        public void Handle(TEvent evt)
        {
            if (!(evt is T))
            {
                throw new ArgumentException("This handler does not support the event type " + evt.GetType().FullName); 
            }
    
            Handle((T) evt);
        }
    }
    

    您的特定事件处理程序将从这个抽象基类派生,类似于下面的代码示例:

    public class SpecificEventHandler: HandlerBase<SpecificEvent>
    {
       public override void Handle(SpecificEvent evnt)
       {
          ....
       }
    }
    


    然后可以将问题中的代码简化为:

    foreach (var evt in eventItems)
    {
        ...
        dynamic eventHandler = ResolveEventHandler(evt.GetType().Name);
        eventHandler.Handle(evt);
    }
    


    另外,不允许使用 TEvent 本身作为泛型类型参数,将tevent声明为抽象类或将其转换为接口(注意 new() 我使用的约束 手柄座 上面,它只允许将conrete、instantiable类型用作泛型类型参数)。使用 特文特 本身作为上面显示的handlerbase类i的泛型类型参数将导致两个 把手 具有相同签名的方法,导致编译错误。