c# - 在此示例中,如何将具有泛型类型的从同一接口继承的不同对象存储在单个变量中?
问题描述
假设我有一个由 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>
into IService<IEntity>
。这让我有点吃惊,因为 EntityTypeA 实现了 IEntity 并且 Service 实现了 IService ...
所以我的问题是:如何将所有这些通用服务存储在一个变量中,以便我可以通过管理器的一种方法轻松获取它们?我希望这个管理器是一个负责管理所有这些服务的单一实例,但我不知道如何在其中保存所有这些通用类。
解决方案
您不能存储Service<EntityTypeA>
intoIService<IEntity>
因为在 上IService
是不变的T
。泛型类型参数默认情况下是不变的,除非您另外声明了它们。一般Foo<Derived>
不能分配给。请参阅这篇文章了解原因。Foo<Base>
根据 的内容// stuff
,IService
您可以潜在地使T
covariant,允许您将 type 的值IService<EntityTypeA>
(因此Service<EntityTypeA>
)分配给 type 的变量IService<IEntity>
。
您可以通过在 上添加out
修饰符来做到这一点T
:
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!
推荐阅读
- jmeter - 在 Jmeter 中是否有一个只报告事务控制器响应的侦听器?
- java - 并发:乘法矩阵。有人可以详细说明 concurrent.multi 以及为什么它在我的代码中不起作用
- oracle11g - Oracle - 如何以最小/最大速率显示 [Apartments] 总数(嵌套聚合函数问题)
- salesforce - 如何使用测试未运行检查为代码块创建测试场景
- java - 我无法通过命令提示符运行基本程序,但我可以通过 IDE 运行它
- airflow - 计划的 DAG 未运行。我如何诊断问题?
- python - 拆分文本而不丢失分隔符
- php - 将 ID 重写为 .htaccess 中的斜线
- python - 为什么这是遍历 MultiWidget 的子小部件的正确方法?
- c - 这种“结构继承”技术是否保证有效,还是依赖于实现?