c# - 无法使用 'where' 类型约束转换泛型参数?

标签 c# generics

我有一个基类:

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 : DomainEventDomainEventSubscriber<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然后出现在HandleEventinput位置.你可以把它变成一个接口(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/

相关文章:

java - 如何测试方法返回类型是否匹配 List<String>

java - 如何在混合 Java 版本的世界中使用泛型?

c# - clearcanvas 检查文件是否为 dicomdir

c# - 读取动态添加的 header 的 Gridview header 值

c# - 如何在 Windows Phone 中禁用多点触控?

c# - 如何实现ASP.Net级联DropDownList控件?

generics - 如果我在函数内部创建引用,如何将泛型类型与需要生命周期参数的特征绑定(bind)?

generics - 如何获取类型参数的名称?

java - 有没有办法使用Java泛型类型来编写排序算法?

c# - 从 C# 的 Regex.Matches 返回的数组顺序是否保证按文本顺序排列?