Получить имя метода с помощью выражения Lambda
Я пытаюсь получить имя метода для типа с использованием выражения лямбда. Я использую Windows Identity Foundation и должен определить политики доступа с именем типа с пространством имен в качестве ресурса и именем метода в качестве действия. Вот пример.
Это тип, из которого я получаю имя типа и имя метода:
namespace My.OrderEntry {
public class Order {
public void AddItem(string itemNumber, int quantity) {}
}
}
Вот как я хотел бы определить политику доступа через DSL:
ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim());
Из этого утверждения я хотел бы получить "My.OrderEntry.Order" в качестве ресурса и "AddItem" в качестве действия. Получение имени типа с пространством имен не представляет проблемы, но я не думаю, что могу использовать лямбда для метода, который я пытаюсь сделать.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Func<T, delegate???> action) {} //this is where I don't know what to define
Можно ли это делать? Есть ли другой способ делать такие вещи без использования магических строк?
Ответы
Ответ 1
Есть два способа сделать это:
1: вы можете сделать перегрузки, которые принимают различные делегаты Func
и Action
(например, Expression<Func<T, Func<TParam1,TParam2, TReturn>>
). Обратите внимание, что вашим вызывающим абонентам необходимо явно указать общие параметры либо в вызове метода, либо путем создания делегата. Это будет использоваться следующим образом:
ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim());
2: Вы можете взять Expression<Action>
, который содержит вызов метода, и разобрать MethodInfo
, который вызывается из дерева выражений. Это будет использоваться следующим образом:
ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim());
Ответ 2
Похоже, это то, что вы ищете, если хотите, чтобы имя метода делегирования действия передавалось в функцию "Выполнение".
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Expression<Action<T, string, int>> action)
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
// use actionMethodName ("AddItem" in the case below) here
}
Это позволит вам вызвать метод, подобный этому...
ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim());
Ответ 3
Недавно я сделал что-то на работе, где вы определили метод с использованием лямбда, который затем получил внутренний объект. Вы также можете использовать строки или передать в MethodInfo, но первый из них не является безопасным для типов (и опечатки представляют большой риск), а последнее не очень элегантно.
В основном у меня был такой метод (это не точный метод, он немного более продвинутый):
public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector);
Ключ здесь - вещь "Выражение", это позволяет вам "выбрать" способ, подобный этому:
SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs);
Селектор методов превращается в дерево выражений, из которого вы можете извлекать разные биты данных. Я не помню точно, как выглядит результирующее дерево, это также зависит от того, как выглядят ваши лямбды.
Ответ 4
Вместо этого вы можете передать его как действие, которое не вызывает никакого возвращаемого типа. Это все еще немного грязно, потому что вам нужно передать некоторые аргументы методу для его компиляции.