如何从Expression <action <t>&gt;中获取值?

时间:2016-05-02 18:14:57

标签: c# linq-expressions hangfire

我有一个非常奇怪的测试,我正在编写测试,如果发送电子邮件。我们使用hangfire所以我有一个包装器IHangfireWrapper,以便我可以模拟Enqueue方法。此Enqueue方法采用一个参数(Expression<Action<T>>)。

因此,如果我想使用这种方法,它看起来就像这样。

_ServiceProvider.HangfireWrapper
    .Enqueue<HangfireTasks>(x => x.SendEmail(subject, body, to));

我在传递主题,身体和到达的字符串。

所以这是棘手的部分。我想模仿这个电话,所以我可以看看主题,正文和字符串。

我有这个代码可以工作,我可以找回我想要的字符串,但它非常难看。

var hangfireMock = new Mock<IHangfireWrapper>();

string body = null;
string subject = null;
string to = null;

hangfireMock.Setup(x => x.Enqueue(It.IsAny<Expression<Action<HangfireTasks>>>()))
    .Callback<Expression<Action<HangfireTasks>>>(expr =>
    {
        object parameters = ((ConstantExpression)((MemberExpression)((MethodCallExpression)expr.Body).Arguments[0]).Expression).Value;
        body = (string)parameters.GetType().GetField("body").GetValue(parameters);
        subject = (string)parameters.GetType().GetField("subject").GetValue(parameters);
        to = (string)parameters.GetType().GetField("to").GetValue(parameters);
    });

有更好/更短的方法吗? (这个代码甚至有意义吗?)

1 个答案:

答案 0 :(得分:3)

你正在做的事情可能适用于你的编译器版本,只要你总是像那样形成lambda。

以下是一些不起作用的示例lambdas:

x => x.SendEmail("subject", "body", "to")
x => x.SendEmail(subject, subject, to)

你应该做的是取Arguments调用SendEmail并通过为它创建一个lambda表达式然后编译它来评估它们中的每一个:

var arguments = ((MethodCallExpression)expr.Body).Arguments;
subject = Expression.Lambda<Func<string>>(arguments[0]).Compile()();
body = Expression.Lambda<Func<string>>(arguments[1]).Compile()();
to = Expression.Lambda<Func<string>>(arguments[2]).Compile()();

编译表达式相对昂贵,因此解释表达式是有意义的。 You have that choice on .Net Core您可能还将在.Net Framework的未来版本中使用。