【发布时间】:2013-12-15 11:11:31
【问题描述】:
我正在尝试创建一个通用函数,该函数将采用 2 个结构实例并使用传入实例的值创建一个新实例。我大部分时间都在那里,但我无法弄清楚如何构建表达式树以将新值作为 MemberInit 中的参数(第一次使用表达式树)。
我尽量避免产生垃圾(所以不要装箱)。
这是我目前所拥有的:
private static readonly Dictionary<Type, FieldInfo[]> fieldInfoCache = new Dictionary<Type, FieldInfo[]>();
private static readonly Dictionary<FieldInfo, dynamic> compiledDelegates = new Dictionary<FieldInfo, dynamic>();
private static T Lerp<T>(T start, T end, float amount) where T : new()
{
FieldInfo[] fields;
var type = typeof(T);
if(!fieldInfoCache.TryGetValue(type, out fields))
{
fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
fieldInfoCache.Add(type, fields);
}
var binds = new List<MemberBinding>();
foreach(var fieldInfo in fields)
{
dynamic getter;
if(!compiledDelegates.TryGetValue(fieldInfo, out getter))
{
var targetExp = Expression.Parameter(type, type.Name);
var fieldExp = Expression.Field(targetExp, fieldInfo);
getter = Expression.Lambda(typeof(Func<,>).MakeGenericType(type, fieldInfo.FieldType), fieldExp, targetExp).Compile();
compiledDelegates.Add(fieldInfo, getter);
}
var startVal = getter.Invoke(start);
var endVal = getter.Invoke(end);
//This needs to be assigned to something
var newVal = fieldInfo.FieldType.IsAssignableFrom(typeof(float)) ? LerpF(startVal, endVal, amount) : Lerp(startVal, endVal, amount);
var fieldParamExp = Expression.Parameter(fieldInfo.FieldType, "newVal");
var bind = Expression.Bind(fieldInfo, fieldParamExp);
binds.Add(bind);
}
//How do I fix these two lines?
var memberInit = Expression.MemberInit(Expression.New(type), binds);
var result = Expression.Lambda<Func<T>>(memberInit).Compile().Invoke();
return result;
}
我被难住的部分是如何将值输入最后两行而不导致装箱
【问题讨论】:
-
那么,您尝试创建的代理应该为每个
float字段调用LerpF()吗?在这种情况下,您需要创建一个调用该方法的表达式,而不是直接调用它。 -
是的,没错,但为什么需要在表达式中完成呢?我想也许如果我将这一切捆绑到一个表达式中......但我计划有一组表达式用于从字段中获取数据,一组表达式用于构造新对象。除非这可能使构建部分更容易?
标签: c# c#-4.0 dynamic expression-trees