2012-05-31 42 views
8

我有以下情形的一般方法:调用与正确的派生类型

我有三个类,让我们称他们为ABC。他们所有的共同之处在于它们从相同的接口ISomeInterface继承,并且它们是使用实体框架映射到实体的类。

我有一个方法接收实现此接口的对象列表,但对象本身将是ABC的实例。

方法外壳看起来像这样

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>(); 
    ... 
    } 
} 

的问题是,因为TISomeInterface线var set = repository.Set<T>();失败在这种情况下,而不是实际类型(ABC),所以它给出了一个与给定的类型无关的异常,这是可以理解的。

所以我的问题是:我如何调用ProcessEntity的列表中的对象的实际类型,而不是它们实现的接口类型。

回答

13

将实体传递给ProcessEntity时,您可以应用dynamic关键字。在这种情况下,实体类型的实体将在运行时确定。

public void MyMethod(List<ISomeInterface> entityList) 
{ 
    foreach(var entity in entityList) 
    { 
    dynamic obj = entity; 
    ProcessEntity(obj); 
    } 
} 
+1

这样做的伎俩。我将'ProcessEntity(obj);'改变为'ProcessEntity(obj as dynamic);',并且结果很好。动态使用我不知道。非常感谢:) –

+0

@ØyvindKnobloch-Bråthen是的,我很喜欢这个运行时间典型 –

2

好了,你可以做一个访问者样伎俩,并使用以下解决方法:

  1. 定义的方法Process(EntityProcessor ep)ISomeInterface
  2. A实现它就像ep.ProcessEntity<A>(this)(并以同样的方式在BC
  3. 而不是你的循环中的ProcessEntity(entity),只需拨打entity.Process(this)

(方法名称也许不干净,但你应该明白我的意思)

+0

这会工作,但lazyberezovsky的答案更清洁,因为这意味着我不必把更多的逻辑放入A,B和C(这里有20个这样的类型,不是3;)) –

+0

@Øyvind:好吧,我的解决方案需要更多的工作,但它在编译时检查所需方法的存在。同样,它可能会稍微快一点。 – Vlad

+0

我明白了你的观点,但是使用动态方法根本不需要任何方法,而且我更希望类A,B和C对此功能也没有任何了解。这也意味着我不必记得为创建的应该遵循相同模式的新类添加额外的功能。 –

2

你可以使用反射来获取泛型方法定义,然后调用它,如:

var method = typeof(ClassContainingProcessEntity) 
    .GetMethod(ProcessEntity) 
    .MakeGenericMethod(entity.GetType); 
method.Invoke(this, entity); 

您可以按类型缓存该方法,并且如果性能至关重要,则可以在运行时使用某种委托工厂进行编译。

或者你可以使用Visitor pattern

+0

是的,两者都应该工作,如果我在这里没有更好的答案,我正在考虑去反射路线。看起来像动态修复,但这很干净。感谢您的输入 :) –