从通用接口强制转换为对象返回null

时间:2019-02-05 16:57:59

标签: c# .net dependency-injection .net-core inversion-of-control

我有这种情况

function someFunc() {
  alert("function loaded!!")
}
    
someFunc(); // will load on page load
document.getElementById("ano").addEventListener("click", someFunc); // will load when `ano` element invokes the change listener

和多种实现方式

<button id="ano">Click Me</button>

我正在使用ServiceProvider的interface INotification<T> { Task Handle(T t) } 来获取所有实现 这样

class Notification1 : INotification<SomeEvent>
{
    //.... 
}


class Notification2 : INotification<SomeEvent>
{
    //.... 
}

GetServices(Type)中,我获得了实现async Task RunAsync<TNotification>(TNotification notification) { Type notificationType = notification.GetType(); var handlerType = typeof(INotification<>).MakeGenericType(notificationType); var handlers = _serviceProvider.GetServices(handlerType); foreach (var handler in handlers) { var instance = handler as INotification<TNotification>; await instance.Handle(notification); } } 的处理程序。在foreach循环中,我试图对handlers进行强制转换并触发Handle方法。

但是强制转换失败

INotification<T>

我得到 null

我的代码有什么问题?

2 个答案:

答案 0 :(得分:1)

var instance = handler as INotification<TNotification>;看起来很奇怪。看起来您通常将TNotification作为某种通知类,例如Notification1。因此,结果转换为

    handler as INotification<Notification1>

的确会失败,因为代码似乎正在创建handlerType的{​​{1}}(在示例情况下为TNotification),通常不会是Notification1(也可能- Recursive generic types

您可能想要类似

Notification1 : INotificaton<Notification1>

请注意,您必须指定事件类型(async Task RunAsync<TNotification, TEvent>(TNotification notification) where TNotification : INotification<TEvent> { ... var instance = (INotification<TEvent>)handler; … } ),因为单个类可能实现多个接口,例如

TEvent

并且无法根据类来确定要投射到哪个对象。

答案 1 :(得分:1)

基于构造的通用类型

UNION

我相信泛型可能会引起混淆。

请考虑为服务提供商使用通用的var handlerType = typeof(INotification<>).MakeGenericType(notificationType); 扩展名,该扩展名将简化以上代码。

GetServices<T>()

由于具有强类型的泛型,因此简化了对处理程序的调用,因为它们已经是所需的类型

这也可以重构为使用async Task RunAsync<TEvent>(TEvent @event) { var handlers = _serviceProvider.GetServices<INotification<TEvent>>(); foreach (var handler in handlers) { await handler.Handle(@event); } } 异步处理所有通知,而不是像Task.WhenAll循环那样按顺序

foreach