我看到了这个构建动态表达式树时的问题和表达式/语句树,因为我对表达式树还不熟悉,所以仍然在努力理解如何实现我想要的。
下面是一个人工制造的对象
public class TestObject
{
public TestObject()
{
ClassList = new List<Class>();
}
public int Age { get; set; }
public List<Class> ClassList { get; set; }
}
public class Class
{
public string Name { get; set; }
public int ClassId { get; set; }
}
在运行时,我遍历每个属性并生成一个Delegate,用于将该属性转换为字符串。这一切都已经实现。现在我需要处理的问题是,对于List类型,我需要能够在ClassList属性中应用一组操作,所以我需要一个foreach循环来实现这一点。
目前我的代码如下:
//type==TestObject at runtime
//propertyName == "ClassList"
ParameterExpression recordExpression = Expression.Parameter(type, "record");
memberExpression = MemberExpression.Property(recordExpression, propertyName);
Type getEnumerableDelegateType =
typeof(Func<,>).MakeGenericType(new Type[] { type, memberExpression.Type});
var getList = Expression.Lambda(getEnumerableDelegateType, memberExpression, recordExpression);
GetList被编译和调用后按预期返回List。我正在努力创建一个表达式,该表达式将使用lambda表达式的结果,并迭代它应用我已为每个Class项创建的一组操作。
最终,我正在寻找一个lambda签名,以匹配下面的overallAction签名。
var getListFunc = new Func<TestObject, List<Class>>((TestObject obj1) => obj1.ClassList);
Action<List<Class>> listAction = delegate(List<Class> data)
{
foreach (var dataChannelWithUnitse in data)
{
//Apply generated delegate
}
};
Action<TestObject> overallAction = delegate(TestObject data)
{
var x = getListFunc.Invoke(data);
listAction.Invoke(x as List<Class>);
};
希望能得到任何帮助,帮助我理解如何完成这个任务。
我现在得到的是这个,但它抛出异常:变量 'Input' 的类型为 'TestObject',在范围 '' 中引用,但未定义
var typeParam = Expression.Parameter(type, "Input");
var listVariable = Expression.Variable(memberExpression.Type, "List");
var enumerator = Expression.Variable(typeof(IEnumerator<>).MakeGenericType(dataType));
var enumeratorType = typeof(IEnumerator<>).MakeGenericType(dataType);
var enumerableType = typeof(IEnumerable<>).MakeGenericType(dataType);
var enumerableParam = Expression.Parameter(enumerableType, "ExtractedCollection");
var getEnumeratorFunc = Expression.Call(enumerableParam, enumerableType.GetMethod("GetEnumerator"));
var getEnumeratorLambda = Expression.Lambda(getEnumeratorFunc, enumerableParam);
var t1 = Expression.Assign(listVariable, Expression.Invoke(getListLambda, typeParam));
var t2 = Expression.Assign(enumerator, Expression.Invoke(getEnumeratorLambda, listVariable));
var @break = Expression.Label();
var funcBlock = Expression.Block(
new ParameterExpression[] { listVariable, enumerator},
t1,
t2,
Expression.Loop(
Expression.IfThenElse(
Expression.NotEqual(Expression.Call(enumerator,typeof(IEnumerator).GetMethod("MoveNext")),Expression.Constant(false)),
Expression.Invoke(enumerableExpressions[0],Expression.Property(enumerator, "Current")),
Expression.Break(@break))
, @break), typeParam);
Expression<Action<TestObject>> lm = Expression.Lambda<Action<TestObject>>(funcBlock,recordExpression);
var d = lm.Compile(); **//this is exceptioning with " variable 'Input' of type 'TestObject' referenced from scope '', but it is not defined**
List<T>
实际上有一个.ForEach()
方法,你可以调用它。这并不适用于任何IEnumerable
,但在这种特定情况下,它可以帮助你简化代码。 - Jeroen Mostert