2014-02-10 54 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,成功的作品。