Tôi đang tạo cây biểu thức và có một tình huống mà tôi cần phải tạo một lambda trong lambda khác và lưu trữ bên trong một lớp và thêm lớp đó trong cây biểu thức. Đây là ví dụ đơn giản về những gì tôi đang cố gắng để làm (mã này không biên dịch):Biểu thức cây - biên dịch bên trong lambda - phạm vi độ phân giải
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace SimpleTest {
public class LambdaWrapper {
private Delegate compiledLambda;
public LambdaWrapper(Delegate compiledLambda) {
this.compiledLambda = compiledLambda;
}
public dynamic Execute() {
return compiledLambda.DynamicInvoke();
}
}
public class ForSO {
public ParameterExpression Param;
public LambdaExpression GetOuterLambda() {
IList<Expression> lambdaBody = new List<Expression>();
Param = Expression.Parameter(typeof(object), "Param");
lambdaBody.Add(Expression.Assign(
Param,
Expression.Constant("Value of 'param' valiable"))
);
lambdaBody.Add(Expression.Call(
null,
typeof(ForSO).GetMethod("Write"),
Param)
);
Delegate compiledInnerLambda = GetInnerLambda().Compile();
LambdaWrapper wrapper = new LambdaWrapper(compiledInnerLambda);
lambdaBody.Add(Expression.Constant(wrapper));
//lambdaBody.Add(GetInnerLambda());
return Expression.Lambda(
Expression.Block(
new ParameterExpression[] { Param },
lambdaBody));
}
public LambdaExpression GetInnerLambda() {
return Expression.Lambda(
Expression.Block(
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Expression.Constant("Inner lambda start")),
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Param),
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Expression.Constant("Inner lambda end"))
)
);
}
public static void Write(object toWrite) {
Console.WriteLine(toWrite);
}
public static void Main(string[] args) {
ForSO so = new ForSO();
LambdaWrapper wrapper = so.GetOuterLambda().Compile()
.DynamicInvoke() as LambdaWrapper;
wrapper.Execute();
//(so.GetOuterLambda().Compile().DynamicInvoke() as Delegate).DynamicInvoke();
}
}
}
Vấn đề là ở GetInnerLambda().Compile()
dòng trong GetOuterLambda
phương pháp. Tôi biết một giải pháp - đó là phần nhận xét của mã. Với điều đó, mọi thứ hoạt động tốt, nhưng tôi cần một wrapper như giá trị trả về, không phải là subtree biểu thức (có thể là ok để lưu trữ bên trong lambda subtree trong LambdaWrapper, và biên dịch nó sau này, nhưng cùng một vấn đề xảy ra).
Lỗi tôi nhận được là Unhandled Exception: System.InvalidOperationException: variable 'Param' of type 'System.Object' referenced from scope '', but it is not defined
.
Nếu tôi thêm Param
để chặn biến trong lambda bên trong, biên dịch mã, nhưng Param không có giá trị được chỉ định trong lambda bên ngoài (và điều đó có ý nghĩa).
Cách này có thể được giải quyết?
Cảm ơn cho câu trả lời.Những gì tôi không thích về cách tiếp cận này là những lambdas là các chức năng thực tế, và chúng có thể có các tham số của chúng (tôi không bao gồm phần đó trong câu hỏi vì tôi không có vấn đề gì), và Param không chỉ biến tôi cần phải truy cập (có thể có rất nhiều người trong số họ), vì vậy tôi không nghĩ rằng các thông số nhân tạo addig để giải quyết phạm vi là giải pháp rất thanh lịch. –
Câu trả lời được cập nhật có thể chỉ hoạt động với tôi, nhưng tôi sẽ phải kiểm tra khi nào tôi quay lại máy tính đang hoạt động. Cảm ơn ... –
Tôi đã kiểm tra xem điều này có phù hợp với tôi hay không. Hầu hết :). Tôi đã lấy nó một bước xa hơn và tạo ra DynamicExpression để tạo ra thể hiện của LambdaWrapper. Tôi đã phải tạo ra các chất kết dính, vì vậy, linh hồn này đòi hỏi nhiều công việc hơn, nhưng tôi đã có chúng trong dự án chính của tôi. Cảm ơn bạn đã quan tâm đến việc giải thích vấn đề này :) –