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

前端之家收集整理的这篇文章主要介绍了c# – 转换泛型参数,其中’where’类型约束不可能?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个基类:
  1. public abstract class DomainEventSubscriber<T> where T : DomainEvent
  2. {
  3. public abstract void HandleEvent(T domainEvent);
  4. public Type SubscribedToEventType() { return typeof(T); }
  5. }

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

  1. public class DomainEventPublisher
  2. {
  3. private List<DomainEventSubscriber<DomainEvent>> subscribers;
  4.  
  5. public void Subscribe<T>(DomainEventSubscriber<T> subscriber)
  6. where T : DomainEvent
  7. {
  8. DomainEventSubscriber<DomainEvent> eventSubscriber;
  9. eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;
  10.  
  11. if (!this.Publishing)
  12. {
  13. this.subscribers.Add(eventSubscriber);
  14. }
  15. }
  16. }

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

  1. 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接口,并从中派生出你当前的类:

  1. public interface IDomainEventSubscriber
  2. {
  3. void HandleEvent(DomainEvent domainEvent);
  4. Type SubscribedToEventType();
  5. }
  6.  
  7. public abstract class DomainEventSubscriber<T> : IDomainEventSubscriber
  8. where T : DomainEvent
  9. {
  10. void IDomainEventSubscriber.HandleEvent(DomainEvent domainEvent)
  11. {
  12. if (domainEvent.GetType() != SubscribedToEventType())
  13. throw new ArgumentException("domainEvent");
  14.  
  15. HandleEvent((T)domainEvent);
  16. }
  17.  
  18. public abstract void HandleEvent(T domainEvent);
  19.  
  20. public Type SubscribedToEventType() { return typeof(T); }
  21. }

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

  1. public class DomainEventPublisher
  2. {
  3. private List<IDomainEventSubscriber> subscribers;
  4.  
  5. public void Subscribe<T>(DomainEventSubscriber<T> subscriber)
  6. where T : DomainEvent
  7. {
  8. if (!this.Publishing)
  9. {
  10. this.subscribers.Add(eventSubscriber);
  11. }
  12. }
  13. }

猜你在找的C#相关文章