Вам нужно передать Expression
вместо Action
. На самом деле не так сложно использовать деревья выражений для этого, когда вы понимаете, как выглядит дерево.
Строка кода:
(MyClass c) => c.TestMethod();
Может быть разбит как лямбда-выражение (весь блок), содержащее один параметр (c
, слева) и тело (c.TestMethod()
, справа).
Тогда «тело» - это вызов метода для конкретного объекта (который является параметром c
), фактического метода (TestMethod
) и набора аргументов (в этом случае нет есть).
Визуально:
LambdaExpression [ (MyClass c) => c.TestMethod() ]
/ \
/ \
/ \
Parameters Body [ MethodCallExpression: c.TestMethod() ]
| / \
| / \
1: MyClass c Object [c] \
/\
/ \
/ \
Method [TestMethod] Arguments [Empty]
То, что вы хотите - это имя метода, внутри выражения вызова метода, внутри тела лямбда-выражения. Таким образом, код, чтобы получить это:
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());