【问题标题】:Expression.Call causes "Static method requires null instance, non-static method requires non-null instance"Expression.Call 导致“静态方法需要空实例,非静态方法需要非空实例”
【发布时间】:2019-09-03 17:19:57
【问题描述】:

我查看过类似的 SO 问题,但无法弄清楚为什么我的问题不起作用。 我需要将 Func<string, bool> 值转换为要在 Moq 框架中使用的表达式,但在尝试将 Func 转换为表达式时无法传递错误。

这是错误:

静态方法需要空实例,非静态方法需要 非空实例。

这是我的示例代码:

using System;
using System.Linq.Expressions;

namespace ConsoleApp1
{
    class Program
    {
        public class MyObject
        {
            public void Add<T>(Func<T, bool> value)
            {
                // Line below causes error: Static method requires null instance, 
                // non-static method requires non-null instance.
                Expression<Func<T, bool>> expression =
                    Expression.Lambda<Func<T, bool>>(Expression.Call(value.Method));


                // I need to use the expression for the line below that is commented out
                // (for context reasons I have included this)
                //_myMock.Setup(m => m.MyMethod(key, It.Is(expression))).Returns("test");
            }
        }

        public static void Main(string[] args)
        {
            // Call it using:
            var myObject = new MyObject();
            myObject.Add(new Func<string, bool>(x => x.StartsWith("test")));
        }
    }
}

不确定我的函数是静态的还是非静态的,但我会认为它是静态的。我使用调试器检查了 Func 对象,并且有一个名为“IsStatic”的字段设置为 false (value.Method.IsStatic)。有点困惑还有什么可以尝试的。

谢谢。

堆栈跟踪:

System.ArgumentException
  HResult=0x80070057
  Message=Static method requires null instance, non-static method requires non-null instance.
Parameter name: method
  Source=System.Core
  StackTrace:
   at System.Linq.Expressions.Expression.ValidateStaticOrInstanceMethod(Expression instance, MethodInfo method)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression[] arguments)
   at ConsoleApp1.Program.MyObject.Add[T](Func`2 value) in C:\Users\userName\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:line 14
   at ConsoleApp1.Program.Main(String[] args) in C:\Users\userName\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:line 28

【问题讨论】:

  • 我认为这是一个例外 - 你能包括完整的堆栈跟踪吗?如果您可以包含一个真正有帮助的minimal reproducible example - 目前我们看不到MyMethod 等。
  • @JonSkeet 包含相关部分。也没有内在的例外。
  • 不,还有一个我们看不到的相关部分 - 它如何链接到您的代码。是在It.Is 电话中吗?是在Expression.Lambda 吗?是在_myMock.Setup 吗?同样,minimal reproducible example 真的很有帮助。
  • 好吧,我错过了那部分 - 删除 Moq 方面会简化问题,如果你能将它变成我们可以复制、粘贴、编译运行。
  • 肯定更好,谢谢。 (无需导入 Moq 等...)就上下文而言,我认为绝对值得一提 为什么 你正在尝试做某事 - 但这不一定是最低限度的一部分例如,如果你没有走那么远。

标签: c# lambda


【解决方案1】:

您在表达式调用中包装的方法不是静态的。

要调用非静态方法,您需要有效的实例作为 t​​his 传递,如果您实际上使用 func 外部的某个变量,这可能会变得很棘手。您可以进一步检查该方法并查看其声明类型。它的实例将需要使 Expression.Call 工作。


要进行模拟设置,因为这是您的目标,您可以修改您的 Add 方法并直接获取表达式

Add<T>(Expression<Func<T, bool>> expression)
{
    _myMock.Setup(m => m.MyMethod(key, It.Is(expression))).Returns("test");
}

这只会在像这样调用时起作用:

myObject.Add((string x) => x.StartsWith("test"));

【讨论】:

  • 谢谢。我不确定这是否适用于我的 .NET 4.7 语言级别,但似乎效果很好。
  • @Mayron 我认为这从 3.5 开始有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
相关资源
最近更新 更多