我有一个基类:
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);
}
}
}
即使 Subscribe
方法类型受限,我无法从 DomainEventSubscriber<T> subscriber
转换where T : DomainEvent
至 DomainEventSubscriber<DomainEvent>
:
eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;
我将如何执行此转换,或者我是否为难闻的代码味道做好了准备?
最佳答案
协方差
您需要一个具有协变类型参数的接口(interface) T
能够将其转换为 T
的基本类型.例如,IEnumerable<out T>
就是这样一个界面。注意 out
关键字,表示 T
是协变的,因此只能出现在输出位置(例如作为返回值和 setter/getter )。由于协方差,您可以转换 IEnumerable<Dolphin>
至 IEnumerable<Mammal>
: 海豚的可枚举序列肯定也是哺乳动物的可枚举序列。
逆变
但是,您不能制作DomainEventSubscriber<T>
一个接口(interface) IDomainEventSubscriber<out T>
作为T
然后出现在HandleEvent
的input位置.你可以把它变成一个接口(interface) IDomainEventSubscriber<in T>
.
注意 in
关键字,表示 T
是逆变并且只能出现在输入位置(例如作为方法参数)。例如,IEqualityComparer<in T>
就是这样一个界面。由于逆变,你可以投一个 IEqualityComparer<Mammal>
至 IEqualityComparer<Dolphin>
: 如果它可以比较哺乳动物,那么它肯定可以比较海豚,因为它们是哺乳动物。
但这也不能解决您的问题,因为您只能将逆变类型参数转换为 more 派生类型,而您想将其转换为基类型。
解决方案
我建议你创建一个非通用的 IDomainEventSubscriber
接口(interface)并从中派生当前类:
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);
}
}
}
关于c# - 无法使用 'where' 类型约束转换泛型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16387626/