我有以下情况:
我有三个类,我们称它们为A
,B
和C
。它们的所有共同点是它们继承自同一接口ISomeInterface
并且它们是使用实体框架映射到实体的类。
我有一个方法接收实现此接口的对象列表,但对象本身将是A
、B
或C
的实例。
方法外壳如下所示
public void MyMethod(List<ISomeInterface> entityList)
{
foreach(var entity in entityList)
{
ProcessEntity(entity);
}
}
现在,问题出在ProcessEntity
方法上。这是一个通用方法,需要根据类型或实体从数据库中检索匹配元素的表,因此它看起来像这样:
public void ProcessEntity<T>(T entity)
{
using( var repository = new DbRepository())
{
var set = repository.Set<T>();
...
}
}
问题是行var set = repository.Set<T>();
失败,因为在这种情况下T
ISomeInterface
,而不是实际类型(A
,B
或C
),因此它给出了一个与给定类型无关的异常,这是可以理解的。
所以我的问题是:我如何使用列表中对象的实际类型而不是它们实现的接口类型调用 ProcessEntity。
您可以在将实体传递给 ProcessEntity 时应用 dynamic
关键字。在这种情况下,实体的实际类型将在运行时确定。
public void MyMethod(List<ISomeInterface> entityList)
{
foreach(var entity in entityList)
{
dynamic obj = entity;
ProcessEntity(obj);
}
}
好吧,您可以执行类似访问者的技巧并使用以下解决方法:
- 定义
ISomeInterface
中Process(EntityProcessor ep)
的方法 - 在
A
中实现它,就像ep.ProcessEntity<A>(this)
一样(在B
和C
中也是如此) - 与其在循环中
ProcessEntity(entity)
,不如调用entity.Process(this)
。
(方法名称可能不是最干净的,但你应该明白了)
您可以使用反射来获取泛型方法定义,然后调用它,例如:
var method = typeof(ClassContainingProcessEntity)
.GetMethod(ProcessEntity)
.MakeGenericMethod(entity.GetType);
method.Invoke(this, entity);
您可以按类型缓存该方法,如果性能至关重要,则可以在运行时使用某种委托工厂对其进行编译。
或者,您可以使用访客模式