【问题标题】:Getting NullReferenceException when calling expression with multiple parameters in C#在 C# 中调用具有多个参数的表达式时出现 NullReferenceException
【发布时间】:2016-12-17 01:17:04
【问题描述】:

我正在尝试构建接受多个参数的函数。接受一个参数的 Lambda 函数工作正常。这是代码。

var value = 22.55;
var method = typeof(TextWriter).GetMethod("WriteLine", new Type[] { value.GetType() });
ParameterExpression inputParameter = Expression.Parameter(typeof(TextWriter));
var block = Expression.Block(
    inputParameter,
    Expression.Call(inputParameter, method, Expression.Constant(value)));
var function = Expression.Lambda<Action<TextWriter>>(block, inputParameter).Compile();
function(Console.Out);

但是,当我再添加一个我什至不使用的参数时,函数会引发空引用异常。我一定错过了什么,但不知道是什么。这是不起作用的代码:

var value = 22.55;
var method = typeof(TextWriter).GetMethod("WriteLine", new Type[] { value.GetType() });
ParameterExpression inputParameter = Expression.Parameter(typeof(TextWriter));
// Additional parameter here
ParameterExpression inputParameter2 = Expression.Parameter(typeof(double));
var block = Expression.Block(
    // Function block accepts two parameters
    new List<ParameterExpression>() { inputParameter, inputParameter2 },
    Expression.Call(inputParameter, method, Expression.Constant(value)));

var function = Expression.Lambda<Action<TextWriter, double>>(block, inputParameter, inputParameter2).Compile();
// ....aaand null exception here. Why?
function(Console.Out, value);

我在这里做错了什么?

【问题讨论】:

    标签: c# lambda expression


    【解决方案1】:

    从您的评论来看,您误解了您传递给Block 的内容。 Block的variables参数是定义局部变量,而不是参数。

    var block = Expression.Block(
        // Function block accepts two parameters
        new List<ParameterExpression>() { inputParameter, inputParameter2 },
        Expression.Call(inputParameter, method, Expression.Constant(value)));
    

    应该很简单

    var block = Expression.Block(Expression.Call(inputParameter, method, Expression.Constant(value)));
    

    你目前正在做的相当于:

    void function(TextWriter tw, double d) {
        TextWriter tw = default(TextWriter);
        double d = default(double);
    
        tw.WriteLine(22.55);    
    }
    

    而你实际上只是想要:

    void function(TextWriter tw, double d) {
        tw.WriteLine(22.55);    
    }
    

    另外,您实际上并没有使用第二个参数。完整的工作代码是:

    var method = typeof(TextWriter).GetMethod("WriteLine", new Type[] { typeof(double) });
    ParameterExpression inputParameter = Expression.Parameter(typeof(TextWriter));
    ParameterExpression inputParameter2 = Expression.Parameter(typeof(double));
    var block = Expression.Block(Expression.Call(inputParameter, method, inputParameter2));
    var function = Expression.Lambda<Action<TextWriter, double>>(block, inputParameter, inputParameter2).Compile();
    function(Console.Out, 35.5);
    

    您的第一个代码有效,因为您使用了不同的块重载。您没有为inputParameter 声明局部变量,而是将其作为表达式本身传递。所以,代码看起来像这样:

    void function(TextWriter tw, double d) {
        tw; //Illegal for the C# compiler, but not illegal as an expression. This will do nothing.
        tw.WriteLine(22.55);    
    }
    

    【讨论】:

    • 我以为Expression.Block的第一个参数声明了函数参数。我被我正在查看的示例代码中的变量名称误导了。现在一切看起来都很棒。
    猜你喜欢
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多