我需要调用一个泛型方法,该方法将泛型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的工作,但我无法理解。
部分答案可以在这个问题的答案中找到:
答案 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,它可以成功运行。