2010-02-22 23 views
17

Próbuję uzyskać nazwę metody na typ za pomocą wyrażenia lambda. Używam Windows Identity Foundation i muszę zdefiniować zasady dostępu z nazwą typu z przestrzenią nazw jako zasobem i nazwą metody jako akcją. Oto przykład.Uzyskaj nazwę metody za pomocą wyrażeń Lambda

Jest to rodzaj chciałbym być coraz nazwę typu i nazwy metody od:

namespace My.OrderEntry { 
    public class Order { 
     public void AddItem(string itemNumber, int quantity) {} 
    } 
} 

ten sposób chciałbym określić zasady dostępu przez DSL:

ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim()); 

Od to oświadczenie, chciałbym, aby "Moja.OrderEntry.Order" jako zasób i "AddItem" jako działanie. Uzyskanie nazwy typu z przestrzenią nazw nie jest problemem, ale nie sądzę, żebym mógł użyć lambda dla metody, którą próbuję wykonać.

public static IPermissionExp Performing<T>(
    this IActionExp<T> exp, 
    Func<T, delegate???> action) {} //this is where I don't know what to define 

Czy to możliwe? Czy istnieje inny sposób robienia tego bez użycia magicznych ciągów?

+0

Co AddItem ma dodać? – pdr

+0

Nie ma znaczenia, co robi AddItem, potrzebuję tylko nazwy metody bez użycia magicznych ciągów. – awilinsk

+0

To ma znaczenie. Myślę, że gdzie zmierzasz jest Action , ale nie sądzę, że to najlepsza odpowiedź. – pdr

Odpowiedz

7

Istnieją dwa sposoby, aby to zrobić:

1. Można dokonać przeciążeń, które mają różne Func i Action delegatów (np Expression<Func<T, Func<TParam1,TParam2, TReturn>> Pamiętaj, że twoi rozmówcy musiałby określić parametry rodzajowe wyraźnie, zarówno w . wywołanie metody lub poprzez stworzenie powierzyć to byłyby wykorzystywane tak:

ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim()); 

2: można brać Expression<Action> który zawiera wywołanie metody i analizować na zewnątrz MethodInfo wywoływane z drzewa wyrażeń. To byłyby wykorzystywane tak:

ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim()); 
+0

dla 1) czy mogę użyć "obiektu" zamiast "TParam1"? dla 2) w jaki sposób to zrobić bez określania argumentu zerowego? – awilinsk

+0

+1. Nie jestem w stanie wymyślić bardziej ogólnej wersji niż twój drugi przykład. – Skurmedel

+0

@ Wili: 1) Nie - delegaci nie są kowariantni. 2) Nie. – SLaks

0

Można go przekazać jako działanie, które nie wymusza zwrotu. Nadal jest trochę niechlujny, ponieważ musisz przekazać kilka argumentów do metody, aby ją skompilować.

+1

Działanie zadziała, ale naprawdę nie dbam o argumenty. Czy mógłbym zrobić coś takiego: Func , Func >, Func > – awilinsk

1

Niedawno zrobiłem coś w pracy, gdzie zdefiniowałeś metodę używając lambda, którą wewnętrzny obiekt nazwał. Możesz również użyć ciągów lub przekazać w MethodInfo, ale pierwsza nie jest naprawdę bezpieczna (a literówki są dużym ryzykiem), a druga nie jest zbyt elegancka.

Zasadniczo miałem metody takie jak to (nie jest to dokładna metoda jest nieco bardziej zaawansowany):

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

Kluczem jest tu „Ekspresja” sprawa ta pozwala „wybierz” metoda taka jak ta:

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

Selektor metod jest tworzony w drzewie wyrażeń, z którego można pobierać różne bity danych. Nie przypominam sobie dokładnie, jak wygląda wynikowe drzewo, zależy to również od wyglądu twoich lambd.

+0

Musiałbym znać podpis metody dla tego. Gdybym miał metody różnych podpisów, musiałbym użyć różnych wyrażeń dla każdej sygnatury, którą napotkam. – awilinsk

+0

Tak, zamiast tego można użyć wyrażenia lub wyrażenia. – Skurmedel

+0

Mam Permorming (to działanie IActionExp exp, Func >). To się nie kompiluje. – awilinsk

3

Wygląda na to jest to, czego szukasz, jeśli chcesz nazwę metody delegata działania przekazany do funkcji Performing.

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 
} 

Pozwoliłoby to wywołać metodę taką jak ta ...

ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim()); 
+1

Oczywiście wymaga to, aby argumenty były znane i określone przez dzwoniącego. Oczywiście nie twoja preferencja nr 1 daje ci komentarze do innych odpowiedzi :-( –

Powiązane problemy