【问题标题】:building a LINQ Expression for unit testing构建用于单元测试的 LINQ 表达式
【发布时间】:2017-04-07 04:36:10
【问题描述】:

我正在为一个类编写一些单元测试,我正在测试的方法接受一个表达式,我正在尝试构建和表达并将其传递给方法,但我收到以下错误:

System.ArgumentException:静态方法需要空实例, 非静态方法需要非空实例。参数名称:方​​法

[TestClass]
public class WhenFilterProvided : FindSubscriptionsForCurrentUserTestBase
{
    bool filterFuncWasCalled;
    private Func<UserSubscription, bool> filterFunc => (userSubscription) =>
    {
        filterFuncWasCalled = true;
        return userSubscription.SubscriptionId == "petrol.prcies.monthly";
    };

    protected override Expression<Func<UserSubscription, bool>> Filter =>
        Expression.Lambda<Func<UserSubscription, bool>>(Expression.Call(filterFunc.Method));


    [TestMethod]
    public void CallsDetailsRepository()
    {
        UserDetailsRepositoryMock.Verify(x => x.FindAsync("userId", CancellationToken.None), Times.Once);
    }

    [TestMethod]
    public void FilterFuncGetsCalledToFilterSubscriptions()
    {
        Assert.IsTrue(filterFuncWasCalled);
    }
}

【问题讨论】:

  • 不使用 Expression.Call,为什么不简单地调用 filterFunc() 或 filterFunc.Invoke()?
  • 我想你忘了传递 Expression.Call 的参数(表达式中的 userSubscription)

标签: c# linq-expressions


【解决方案1】:

有时会实现匿名方法as instance methods。在您的情况下,匿名方法必须是实例方法,因为您需要访问this 才能访问filterFuncWasCalled。 所以你试图调用一个实例方法,但你没有传递任何实例。您可以通过向实例传递常量表达式来解决此问题:

Expression.Call(Expression.Constant(filterFunc.Target), filterFunc.Method)

但这也不起作用,因为该方法需要一个参数,而您没有传递任何参数。让我们使用我们将用于 lambda 表达式的同一个。这是实现此目的的完整 Filter 属性:

Expression<Func<UserSubscription, bool>> Filter { 
    get {
        var param = Expression.Parameter(typeof(UserSubscription));
        var body = Expression.Call(Expression.Constant(filterFunc.Target), filterFunc.Method, param);
        return Expression.Lambda<Func<UserSubscription, bool>>(body, param);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 2019-01-06
    • 2011-08-04
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多