2010-02-22 8 views
17

Estoy tratando de obtener el nombre de un método en un tipo que utiliza una expresión lambda. Estoy utilizando Windows Identity Foundation y necesito definir políticas de acceso con el nombre de tipo con espacio de nombres como recurso y el nombre del método como acción. Aquí hay un ejemplo.Obtener el nombre del método mediante la expresión de Lambda

Este es el tipo que sería conseguir el nombre del tipo y el nombre del método de:

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

Así es como me gustaría definir la política de acceso a través de DSL:

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

De esa declaración, me gustaría obtener "My.OrderEntry.Order" como el recurso y "AddItem" como la acción. Obtener el nombre del tipo con el espacio de nombres no es problema, pero no creo que pueda usar un lambda para un método como el que trato de hacer.

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

¿Es posible incluso hacer este tipo de cosas? ¿Hay alguna otra manera de hacer este tipo de cosas sin usar cadenas mágicas?

+0

¿Qué se supone que agrega AddItem? – pdr

+0

Realmente no importa lo que haga AddItem, solo necesito el nombre del método sin usar cadenas mágicas. – awilinsk

+0

Es lo que importa. Creo que hacia donde te diriges es una Acción pero no creo que esa sea la mejor respuesta. – pdr

Respuesta

7

Hay dos maneras de hacer esto:

. 1: Se podría hacer sobrecargas que toman los distintos Func y Action delegados (por ejemplo Expression<Func<T, Func<TParam1,TParam2, TReturn>> Tenga en cuenta que las personas que llaman necesitarían para especificar los parámetros genéricos de forma explícita, ya sea en el . llamada al método o creando el delegado esto se usaría como esto:

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

2: Usted podría tomar un Expression<Action> que contiene una llamada a un método, y analizar el MethodInfo siendo llamado desde el árbol de expresiones. Esto se usaría como esto:

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

para 1) ¿podría usar "objeto" en lugar de "TParam1"? para 2) alguna forma de hacerlo sin especificar el argumento nulo? – awilinsk

+0

+1. No puedo encontrar una versión más general que tu segundo ejemplo realmente. – Skurmedel

+0

@Wili: 1) No, los delegados no son covariantes. 2) No. – SLaks

0

En su lugar, podría pasarlo como una acción, lo que no obliga a ningún tipo de devolución. Sin embargo, todavía está un poco desordenado, porque debe pasar algunos argumentos al método para que compile.

+1

La acción funcionaría, pero realmente no me importan los argumentos. ¿Podría hacer algo como: Func , Func >, Func > – awilinsk

1

Hace poco hice algo en el trabajo en el que definía el método a usando una lambda, que el objeto interno tomaba el nombre. También podría usar cadenas o pasar un MethodInfo, pero el primero no es realmente seguro (y los errores tipográficos son un gran riesgo), y el segundo no es muy elegante.

Básicamente tenían un método como este (este no es el método exacto, es un poco más avanzado):

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

La clave aquí es la cosa "Expresión", esto le permite "seleccionar" un método como este:

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

El selector de método se convierte en un árbol de expresiones del que luego puede obtener diferentes bits de datos. No recuerdo exactamente cómo se ve el árbol resultante, también depende de cómo se vean sus lambdas.

+0

Tendría que saber la firma del método para eso. Si tengo métodos de firmas diferentes, tendré que usar diferentes expresiones para cada firma que encuentre. – awilinsk

+0

Sí, podría usar Expression o Expression en su lugar. – Skurmedel

+0

Tengo Permorming (esta IActionExp exp, Func > action). Eso no compila. – awilinsk

3

Parece que esto es lo que está buscando, si desea que el nombre del método de acción delegado pasado a la función Realizar.

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 
} 

Esto le permitiría llamar al método de esta manera ...

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

Por supuesto, sin embargo, esto requiere que los argumentos sean conocidos y establecidos por la persona que llama. Obviamente, no es su preferencia # 1 dado los comentarios sobre otras respuestas :-( –

Cuestiones relacionadas