加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 08:12:57 所属栏目:百科 来源:网络整理
导读:我有一个基类: public abstract class DomainEventSubscriberT where T : DomainEvent{ public abstract void HandleEvent(T domainEvent); public Type SubscribedToEventType() { return typeof(T); }} 还有一个存储DomainEventSubscriber引用的类: publ
我有一个基类:
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);
        }
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读