我有以下方法(用于在单元测试中生成友好的错误消息):
protected string MethodName<TTestedType>(Action<TTestedType> call)
{
return string.Format("{0}.{1}", typeof(TTestedType).FullName, call.Method.Name);
}
但是当我如下调用它时,我没有得到预期的结果:
var nm = MethodName<MyController>(ctrl => ctrl.Create());
运行此代码后,nm
包含 "<Create_CreateShowsView>b__8"
,而不是(如预期的那样)"Create"
.我应该如何更改代码以获得预期的结果?
最佳答案
您需要传递一个 Expression
而不是 Action
.一旦您了解树的外观,使用表达式树实际上并不难。
代码行:
(MyClass c) => c.TestMethod();
可以分解为一个 lambda 表达式(整个 block ),包含一个参数(c
,在左侧)和一个正文(c.TestMethod()
,在右侧)。
“正文”是对特定对象的方法调用(即参数 c
)、实际方法( TestMethod
)和一组参数(在本例中,没有任何)。
视觉上:
LambdaExpression [ (MyClass c) => c.TestMethod() ]
/ \
/ \
/ \
Parameters Body [ MethodCallExpression: c.TestMethod() ]
| / \
| / \
1: MyClass c Object [c] \
/\
/ \
/ \
Method [TestMethod] Arguments [Empty]
您需要的是方法名称,在方法调用表达式内部,在 lambda 表达式的主体内部。所以得到这个的代码是:
static string GetInnerMethodName<T>(Expression<Action<T>> expr)
{
MethodCallExpression mce = expr.Body as MethodCallExpression;
return (mce != null) ? mce.Method.Name : null;
}
当然,这只有在 Expression<Action<T>>
时才有效传入的是真正的方法调用表达式;这个方法的使用者在技术上可以传入任何表达式,在这种情况下,它只会返回 null
.您可以调整它以引发异常、返回默认值或执行您认为合适的任何其他操作。
你不需要做任何特别的事情来使用它 - 它的用法与你原来的方法相同:
string methodName = GetInnerMethodName<MyClass>(c => c.TestMethod());
关于c# - (Action<T>).Name 不返回预期值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2581816/