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



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

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

我有一个通用服务,其中包含这些实体的列表并对其进行了某些操作。该服务有多种不同的实现,都继承自 IService,但假设现在只有一个"服务"。

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>IService因为它在T上是不变的。默认情况下,泛型类型参数是固定的,除非您以其他方式声明它们。Foo<Derived>一般不能分配给Foo<Base>请参阅此帖子了解原因。

根据// stuffIService中的内容,您可以潜在地T,允许您将类型为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!

最新更新