Подтвердить что ты не робот

Получить имя метода с помощью выражения 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

Можно ли это делать? Есть ли другой способ делать такие вещи без использования магических строк?

4b9b3361

Ответ 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

Вместо этого вы можете передать его как действие, которое не вызывает никакого возвращаемого типа. Это все еще немного грязно, потому что вам нужно передать некоторые аргументы методу для его компиляции.