c# – 转换泛型参数,其中’where’类型约束不可能?

我有一个基类:

public abstract class DomainEventSubscriber<T> where T : DomainEvent
{
    public abstract void HandleEvent(T domainEvent);
    public Type SubscribedToEventType() { return typeof(T); }
}

还有一个存储DomainEventSubscriber引用的类:

public class DomainEventPublisher
{
    private List<DomainEventSubscriber<DomainEvent>> subscribers;

    public void Subscribe<T>(DomainEventSubscriber<T> subscriber)
        where T : DomainEvent
    {
        DomainEventSubscriber<DomainEvent> eventSubscriber;
        eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;

        if (!this.Publishing)
        {
            this.subscribers.Add(eventSubscriber);
        }
    }
}

即使订阅方法类型受到约束,我也无法从DomainEventSubscriber转换为< T>订阅者,其中T:DomainEvent到DomainEventSubscriber< DomainEvent>:

eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;

我将如何进行这种转换,或者我是否为一个令人讨厌的代码味道做好准备?

协方差

您需要具有协变类型参数T的接口才能将其转换为基类型T.例如,IEnumerable< out T>就是这样一个界面.注意out关键字,这意味着T是协变的,因此只能出现在输出位置(例如返回值和getter).由于协方差,你可以施放IEnumerable< Dolphin> IEnumerable<哺乳动物>:一系列可观的海豚数量肯定也是一系列哺乳动物.

逆变

但是,您无法使DomainEventSubscriber< T>接口IDomainEventSubscriber< out T>因为T然后出现在HandleEvent的输入位置.您可以将其设置为接口IDomainEventSubscriber< in T>.

注意in关键字,这意味着T是逆变的,并且只能出现在输入位置(例如作为方法参数).例如,IEqualityComparer< in T>就是这样一个界面.由于逆转,你可以施放IEqualityComparer< Mammal> IEqualityComparer< Dolphin>:如果它可以比较哺乳动物,那么肯定它可以比较海豚,因为它们是哺乳动物.

但这也无法解决您的问题,因为您只能将逆变类型参数强制转换为更多派生类型,并且您希望将其转换为基类型.

我建议你创建一个非泛型的IDomainEventSubscriber接口,并从中派生出你当前的类:

public interface IDomainEventSubscriber
{
    void HandleEvent(DomainEvent domainEvent);
    Type SubscribedToEventType();
}

public abstract class DomainEventSubscriber<T> : IDomainEventSubscriber
    where T : DomainEvent
{
    void IDomainEventSubscriber.HandleEvent(DomainEvent domainEvent)
    {
        if (domainEvent.GetType() != SubscribedToEventType())
            throw new ArgumentException("domainEvent");

        HandleEvent((T)domainEvent);
    }

    public abstract void HandleEvent(T domainEvent);

    public Type SubscribedToEventType() { return typeof(T); }
}

然后在内部使用IDomainEventSubscriber而不是DomainEventSubscriber< DomainEvent>:

public class DomainEventPublisher
{
    private List<IDomainEventSubscriber> subscribers;

    public void Subscribe<T>(DomainEventSubscriber<T> subscriber)
        where T : DomainEvent
    {
        if (!this.Publishing)
        {
            this.subscribers.Add(eventSubscriber);
        }
    }
}
本站公众号
   欢迎关注本站公众号,获取更多程序园信息
开发小院