1

我有一个实现泛型接口的具体类型版本的类。我发现如果我在编译时将一个对象传递给我的函数(即使它可能是正确的对象),它仍然被认为是一个对象,因此在运行时失败并出现错误:

Unable to cast object of type 'TestEventHandler' to type 'IDomainEventHandler '1[System.Object]'.

我正在反序列化来自总线的消息(哪些产品对象,应​​该有一个关联的DomainEventHandler<of_deserialized_type>与消息关联的关联。

总而言之,我认为问题IDomainEventHandler<T>不是从 转换`IDomainEventHandler<object>,我将不胜感激有关如何最好地解决此问题并仍然保持通用IDomainEventHandler<T>接口的指导,即使对象被传递到Publish().

[TestClass]
public class InternalMessageHandlerTests
{
    class TestEvent
    {
    }

    class TestEventHandler : IDomainEventHandler<TestEvent>
    {
        public void HandleEvent(TestEvent domainEvent)
        {
        }
    }

    [TestMethod]
    public void Test()
    {
        TestEvent testEvent = new TestEvent();
        object testEventAsObject = testEvent; // compile time type information lost 
        Publish(testEvent); // this is OK :)
        Publish(testEventAsObject); // this fails :(

    }

    public void Publish<T>(T eventToPublish) where T : class
    {
        var handlerInstance = new TestEventHandler();
        IDomainEventHandler<T> converted = (IDomainEventHandler<T>)handlerInstance;
        converted.HandleEvent(eventToPublish);
    }
}
4

2 回答 2

2

您无法转换TestEventHandler为,IDomainEventHandler<object>因为这不安全。如果允许,您可以这样做:

IDomainEventHandler<object> converted = (IDomainEventHandler<object>)new TestEventHandler();
converted.HandleEvent("dsfs");

这是无效的,因为TestEventHandler要求它的论点HandleEventTestEvent

Publish您可以使用反射调用:

TestEvent testEvent = new TestEvent();
object testEventAsObject = testEvent;
var publishMethod = this.GetType().GetMethod("Publish").MakeGenericMethod(testEventAsObject.GetType());
publishMethod.Invoke(this, new object[] { testEventAsObject });
于 2013-05-13T22:45:28.227 回答
1

在这种情况下,不可能支持没有反射的完全通用接口。对于这样一个简单的案例,反射是一个非常糟糕的主意。

对于这些情况,我通常的做法是IDomainEventHandlerDomainEventHandlerBase<T> : IDomainEventHandler这样继承类就可以获得泛型的所有优势,但外部接口可以接受对象。

显然它不是静态安全的,但正如我所说,这里不可能是静态安全的。一旦您将实例分配给object testEventAsObject,您就可以让此变量包含从编译器的角度来看的任何内容(stringint、任何内容)。

对于必须选择正确处理程序的服务总线之类的事情,它看起来像这样:

public interface IDomainEventHandler {
    void HandleEvent(object domainEvent);
    bool CanHandleEvent(object domainEvent);
}

public abstract class DomainEventHandlerBase<T> : IDomainEventHandler {
    public abstract void HandleEvent(T domainEvent);
    public abstract bool CanHandleEvent(T domainEvent);

    void IDomainEventHandler.HandleEvent(object domainEvent) {
        return HandleEvent((T)domainEvent);
    }

    bool IDomainEventHandler.CanHandleEvent(object domainEvent) {            
        return (domainEvent is T) && CanHandleEvent((T)domainEvent);
    }
}

我已经直接写了(没有签入VS)所以可能会出错。

之后,当您收到消息时,只需选择

handlers.First(h => h.CanHandleEvent(domainEvent))
于 2013-05-13T22:49:45.913 回答