使用运行时类型创建通用Func委托

时间:2014-02-10 15:49:40

标签: c# generics reflection delegates

我需要调用一个泛型方法,该方法将泛型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.
        ...
    }

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

这可能是Expression tree和Activator的工作,但我无法理解。

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

Runtime creation of generic Func<T>

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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);
} 

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