繁体   English   中英

在此示例中,如何将具有泛型类型的从同一接口继承的不同对象存储在单个变量中?

[英]How can I store different objects inheriting from same interface, with generic types, in a single variable in this example?

假设我有一个数据 model 由 2 个类组成,它们都实现了相同的接口:

    interface IEntity { }
    class EntityTypeA : IEntity { }
    class EntityTypeB : IEntity { }

我有一个通用服务,其中包含这些实体的列表并对其进行处理。 Service 有多种不同的实现,都继承自 IService,但假设现在只有一个,“Service”。

    interface IService<T> where T : class, IEntity {
        // stuff
        T GetEntity(Func<T, bool> linq);
    }

    class Service<T> : IService<T> where T : class, IEntity {
        // stuff
        IEnumerable<T> _entities;
    }

此时,我可以轻松地为各种实体创建新服务并使用它们。 向它们添加特定类型的新实体,调用方法,将它们取回,而无需手动转换任何东西。

    IService<EntityTypeA> serviceA = new Service<EntityTypeA>();
    IService<EntityTypeB> serviceB = new Service<EntityTypeB>();

一切都好,但现在我想将所有这些服务存储在一个地方,这样我以后可以轻松地获取我想要的服务,而不必将它们全部保存在一个单独的变量中。

最终我希望能够这样做:

    _manager = new ServiceManager();
    _manager.AddService("A", serviceA);
    _manager.AddService("B", serviceB);
    IService<EntityTypeA> serviceA = _manager.GetService<EntityTypeA>("A");

所以我尝试了这样的事情:

class ServiceManager {
        IDictionary<string, IService<IEntity>> _services;

        public void AddService<T>(string key, IService<T> manager) where T : class, IEntity {
            _services[key] = (IService<IEntity>)manager;
        }

        public IService<T> GetService<T>(string key) where T : class, IEntity {
            return (IService<T>)_services[key];
        }
    }

这里的问题是调用 AddService (可能还有 GetService )方法时出现“无效的转换异常”,我无法将Service<EntityTypeA>转换并存储到IService<IEntity>中。 这让我有点吃惊,因为 EntityTypeA 实现了 IEntity 并且 Service 实现了 IService ...

所以我的问题是:如何将所有这些通用服务存储在一个变量中,以便我可以通过管理器的一种方法轻松获取它们? 我希望这个管理器是一个负责管理所有这些服务的单一实例,但我不知道如何在其中保存所有这些通用类。

您不能将Service<EntityTypeA>存储到IService<IEntity>中,因为IServiceT上是不变的。 泛型类型参数默认情况下是不变的,除非您另外声明了它们。 Foo<Derived>通常不能分配给Foo<Base> 请参阅这篇文章了解原因。

根据IService// stuff ,您可以潜在地使T covariant ,允许您将IService<EntityTypeA>类型的值(以及因此Service<EntityTypeA> )分配给IService<IEntity>类型的变量。

您可以通过在T上添加一个out修饰符来做到这一点:

interface IService<out T> where T : class, IEntity {
    // stuff
    T GetEntity(Func<T, bool> linq);
}

如果IService具有采用T的方法(除其他外),这将不起作用:

interface IService<out T> where T : class, IEntity {
    // stuff
    T GetEntity(Func<T, bool> linq);
    void Foo(T t); // compiler error
}

因为这会破坏类型安全:

IService<IEntity> s = new Service<EntityTypeA>();
s.Foo(new EntityTypeB()); // breaks type safety! I can now give Service<EntityTypeA> a EntityTypeB object!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM