2010-02-22 3 views
17

Я пытаюсь получить имя метода для типа с использованием выражения лямбда. Я использую Windows Identity Foundation и должен определить политики доступа с именем типа с пространством имен в качестве ресурса и именем метода в качестве действия. Вот пример.Получить имя метода с помощью выражения Lambda

Это тип я получал бы имя типа и имя метода из:

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 

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

+0

Что следует добавить AddItem? – pdr

+0

Не имеет значения, что делает AddItem, мне просто нужно имя метода без использования магических строк. – awilinsk

+0

Это своего рода вопрос. Я думаю, что вы возглавляете Action , но я не думаю, что это лучший ответ. – pdr

ответ

7

Есть два способа сделать это:

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()); 
+0

для 1) могу ли я использовать «объект» вместо «TParam1»? для 2) любым способом сделать это без указания нулевого аргумента? – awilinsk

+0

+1. Я не могу придумать более общую версию, чем ваш второй пример. – Skurmedel

+0

@Wili: 1) Нет - делегаты не ковариантны. 2) № – SLaks

0

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

+1

Действие будет работать, но мне действительно не нужны аргументы. Могу ли я сделать что-то вроде: Func , Func >, Func > – awilinsk

1

Недавно я сделал кое-что на работе, где вы определили метод с использованием лямбда, который затем получил внутренний объект. Вы также можете использовать строки или пройти в MethodInfo, но первый из них на самом деле не безопасен (и опечатки - большой риск), а последний не очень изящный.

В основном у меня был метод, как это (это не точный метод, это немного более продвинутый):

public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector); 

Ключевым моментом здесь является «выражение» вещь, это позволяет «выбрать» метод, подобный этому:

SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs); 

Селектор свойств выполнен в дереве выражений, из которого вы можете извлекать разные биты данных. Я не помню точно, как выглядит результирующее дерево, это также зависит от того, как выглядят ваши лямбды.

+0

Мне нужно было бы узнать подпись метода для этого. Если у меня есть методы разных подписей, мне придется использовать разные выражения для каждой подписи, с которой я сталкиваюсь. – awilinsk

+0

Да, вы можете использовать Expression или Expression. – Skurmedel

+0

У меня есть Permorming (это IActionExp exp, Func > действие). Это не компилируется. – awilinsk

3

Похоже, это то, что вы ищете, если вы хотите, чтобы имя метода действия делегата передается в функцию исполнительского.

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()); 
+1

Конечно, это требует, чтобы аргументы были известны и указаны вызывающим. Очевидно, что не ваше предпочтение # 1 дало вам комментарии по другим ответам :-( –

Смежные вопросы