2014-02-10 53 views
4

我需要调用一个通用方法,该方法将通用Func作为其参数之一,其中Type参数仅在运行时才为已知。这部分代码是一个对象映射器,它映射源和目标对象之间的属性。 ViewModelBase是被视为“目标”对象的类的根。使用运行时类型创建通用Func委托

,我想调用(上ObjectMapperBuilder定义)的方法,具有这个签名:

public static ObjectMapperBuilder<TTarget> Create(
    Type sourceType, 
    MappingDirection direction, 
    Func<TTarget, IDictionary<String, object>> getDictionaryFromTarget = null 
); 

在我的基类,我想调用上述方法,但使用最派生类型作为我的类型参数:

public ViewModelBase { 
    private ConcurrentDictionary<string, object> _propertyValues; 

    public ViewModelBase (object sourceObject) { 
     Type tTarget = this.GetType(); 

     // 1. How do I create the Func? All it does is return a private member. 
     // This is wrong because it uses a compile-time generic parameter. 
     Func<TTarget,IDictionary<String,object>> myFunc = (vm) => vm._propertyValues; 

     // 2. Ho do I call the Create method using reflection to specify the 
     // TTarget generic parameter at runtime? 
     var myMapper = ObjectMapperBuilder<TTarget>.Create(
      sourceObject.GetType(), 
      MappingDirection.Bidirectional, 
      myFunc 
     ); 
     // Do stuff with myMapper. 
     ... 
    } 

本练习的目的是为了能够在基类的方法中创建映射器。由于我根据源和目标类型缓存映射器,并且不同的派生类型需要不同的映射器,因此必须使用派生类型最多的方法创建映射器。

这可能是Expression树和Activator的工作,但我无法弄清楚。

部分答案可能会在这个问题的答案可以发现:

Runtime creation of generic Func<T>

回答

0

这可能是一个简单的答案,但你可以让你的视图模型的基础型通用,如:

public class ViewModelBase<T> where T : ViewModelBase<T> 

允许你申请继承:

public class SubViewModelBase: ViewModelBase<SubViewModelBase> 

这样,你的实现将只是:

Func<T, IDictionary<string, object>> props = (vm) => vm._propertyValues; 
var mapper = ObjectMapperBuilder<T>.Create(
    sourceObject.GetType(), 
    MappingDirection.Bidirectional, 
    props); 
+0

一个很好的建议,但不是我可以采用的其他原因之一。 –

0

我决定妥协的解决方案。我创建了一个方法“GetProperties”,它可以完成我想要的任务,然后使用Delegate.CreateDelegate将其包装在委托中。

protected static IDictionary<string, object> GetProperties(ViewModelBase viewModel) 
{ 
    return viewModel._propertyValues; 
} 
protected Delegate GetPropertiesFunc() 
{ 
    Type funcType = typeof(Func<,>).MakeGenericType(this.GetType(), typeof(IDictionary<String,object>)); 
    MethodInfo method = typeof(ViewModelBase).GetMethod("GetProperties", 
     BindingFlags.NonPublic | BindingFlags.Static 
    ); 
    return Delegate.CreateDelegate(funcType, method); 
} 

当我以后需要委派为特定的函数功能,我称之为GetPropertiesFunc并把它传递到Activator.CreateInstance,成功的作品。