[英]Can I make a utility method which takes an arbitrary expression as a parameter and calls it?
The exact reasons I might want to do this are a bit hard to go into without posting loads of code, but here's an example of one scenario: 我可能想要这样做的确切原因有点难以在没有发布大量代码的情况下进行,但这是一个场景的示例:
try
{
x.Method(123,"test");
Assert.Fail("No exception thrown");
}
catch (ApplicationException e)
{
StringAssert.StartsWith(e.Message, "Oh no!");
}
I'd like to refactor this to something like... (pseudo-code) 我想重构一下像......(伪代码)
TestExceptionMessage({x.Method(123,"test")},"Oh no!");
void TestExceptionMessage(func,string message)
{
try
{
func();
Assert.Fail("No exception thrown");
}
catch (ApplicationException e)
{
StringAssert.StartsWith(e.Message, message);
}
}
I know C# is pretty flexible with lambdas and so on, but is this pushing it too far or is it reasonable straightforward? 我知道C#对lambdas等非常灵活,但这是推动它太远还是合理的直接?
Yes, and it's pretty straight forward. 是的,而且非常直接。 You can pass a
Action
delegate (or really any delegate type) into a method and call it: 您可以将
Action
委托(或任何委托类型)传递给方法并调用它:
void TestExceptionMessage(Action action, string message)
{
try
{
action();
Assert.Fail("No exception thrown");
}
catch (ApplicationException e)
{
StringAssert.StartsWith(e.Message, message);
}
}
That delegate can be a reference to a method or it could be a lambda expression like this: 该委托可以是对方法的引用,也可以是这样的lambda表达式:
var x = new MyClass();
TestExceptionMessage(() => x.Method(123, "test"),"Oh no!");
However, if you really want to know the expression being used (eg if you want to be able to tell what method is being called) you need to use an Expression<Action>
但是,如果您真的想知道正在使用的表达式 (例如,如果您希望能够告诉正在调用的方法),则需要使用
Expression<Action>
void TestExceptionMessage(Expression<Action> expression, string message)
{
try
{
var methodName = (expression.Body as MethodCallExpression)?.Method.Name;
if (methodName != null)
{
Debug.WriteLine($"Calling {methodName}");
}
expression.Compile().Invoke();
Assert.Fail("No exception thrown");
}
catch (ApplicationException e)
{
StringAssert.StartsWith(e.Message, message);
}
}
And thanks to a little compiler magic, you can call with the same lambda syntax: 感谢一点点编译魔术,你可以使用相同的lambda语法调用:
var x = new MyClass();
TestExceptionMessage(() => x.Method(123, "test"),"Oh no!");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.