【问题标题】:Create a Generic Func delegate using a runtime type使用运行时类型创建 Generic Func 委托
【发布时间】:2014-03-08 01:10:52
【问题描述】:

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

我要调用的方法(在 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.
        ...
    }

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

这可能是表达式树和激活器的工作,但我想不通。

部分答案可能在这个问题的答案中找到:

Runtime creation of generic Func<T>

【问题讨论】:

    标签: c# generics reflection delegates


    【解决方案1】:

    这可能是一个简单的答案,但您能否将您的视图模型基类型设为通用,例如:

    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);
    

    【讨论】:

    • 一个很好的建议,但由于其他原因,我不能采纳。
    【解决方案2】:

    我确定了一个妥协的解决方案。我创建了一个方法“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);
    } 
    

    当我以后需要 Delegate 作为特定的 Func 时,我调用 GetPropertiesFunc 并将其传递给 Activator.CreateInstance,它可以成功运行。

    【讨论】:

      猜你喜欢
      • 2011-05-27
      • 2023-04-05
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多