0

我正在尝试通过解析 XML 模板来执行在运行时动态创建的方法。在编译之前,我立即从表达式 lambda 的“DebugView”中得到以下信息:

.Lambda #Lambda1<Reporting.Core.Formatter+WriterDriver>(
    Reporting.Core.IReportWriter $writer,
    System.Object $data) {
    .Block(
        Reporting.Core.IReportWriter $writer,
        System.Object $data) {
        .Call System.Diagnostics.Trace.WriteLine("Initialize Driver");
        .Call System.Diagnostics.Trace.WriteLine($writer);
        .Block(Reporting.Core.IBannerWriter $bannerWriter) {
            $bannerWriter = .Call $writer.WriteBanner();
            .Call System.Diagnostics.Trace.WriteLine($bannerWriter);
            .Call $bannerWriter.WithLeftEntry(
                "Key1",
                "Value1");
            .Call $bannerWriter.WithLeftEntry(
                "Key 2",
                "Value 2");
            .Call $bannerWriter.WithRightEntry(
                "Another Key",
                "Another Value");
            .Call $bannerWriter.EndBanner()
        }
    }
}

并这样称呼它,确保myReportWriter并且myData不是null先于:

Action<IReportWriter, Object> Formatter = methodExpression.Compile();
Formatter(myReportWriter, myData)

在我的跟踪输出中,在抛出空引用异常之前,我什至没有得到“初始化驱动程序”输出。

仔细观察调试输出显示它实际上是,进入“初始化驱动程序”并在第一个 .Block 内的 $writer 上添加另一个针对 null 的调试检查表明(writer == null) == true. 现在,问题是:为什么 $writer 在被传递到方法调用时为空?

4

1 回答 1

0

第一个 .Block 中的 $writer 和 $data 声明覆盖了来自 .Lambda 的相同声明。

从以下位置更改表达式生成逻辑:

List<Expression> operations = new List<Expression>();
// populate operations...

var methodBody = Expression.Block(new[] {writer, data}, operations);
var lambda = Expression.Lambda<Action<IReportWrite, Object>>(methodBody, writer, data);
while (lambda.CanReduce) lambda.Reduce();

return lambda.Compile()

到:

List<Expression> operations = new List<Expression>();
// populate operations...

var methodBody = Expression.Block(operations);
var lambda = Expression.Lambda<Action<IReportWrite, Object>>(methodBody, writer, data);
while (lambda.CanReduce) lambda.Reduce();

return lambda.Compile()

这产生了一个工作表达式树,如下所示:

.Lambda #Lambda1<Reporting.Core.Formatter+WriterDriver>(
    Reporting.Core.IReportWriter $writer,
    System.Object $data) {
    .Block() {
        .Call System.Diagnostics.Trace.WriteLine("Initialize Driver");
        .Block(Reporting.Core.IBannerWriter $bannerWriter) {
            $bannerWriter = .Call $writer.WriteBanner();
            .Call System.Diagnostics.Trace.WriteLine($bannerWriter);
            .Call $bannerWriter.WithLeftEntry(
                "Key1",
                "Value1");
            .Call $bannerWriter.WithLeftEntry(
                "Key 2",
                "Value 2");
            .Call $bannerWriter.WithRightEntry(
                "Another Key",
                "Another Value");
            .Call $bannerWriter.EndBanner()
        }
    }
}
于 2013-08-20T16:07:39.230 回答