2010-12-05 9 views
6

¿Cómo obtengo los parámetros en un Action<T>? El ejemplo del código debe resaltar lo que intento lograr. Lamento que sea un poco largo.Obtener los parámetros de la acción <T>

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo foo = new Foo(); 
     foo.GetParams(x => x.Bar(7, "hello")); 
    } 
} 

class Foo 
{ 
    public void Bar(int val, string thing) { } 
} 

static class Ex 
{ 
    public static object[] GetParams<T>(this T obj, Action<T> action) 
    { 
     // Return new object[]{7, "hello"} 
    } 
} 

Las únicas opciones que parecen vagamente útiles son GetInvocationList(), Método y Destino. Pero ninguno de ellos parece contener los datos que estoy buscando (creo que es por la forma en que he declarado la Acción). Gracias

EDITAR: No son los tipos que quiero, son los valores reales, como se indica en el bit de código comentado.

+0

@Henk, eso no es así, solo si fue foo.GetParams (x => x.Bar); –

+0

@richK: ¿Estás buscando los vars capturados? –

+0

@Henk - Sí, es correcto – RichK

Respuesta

9

Para hacer eso, en realidad debería ser un Expression<Action<T>>. Entonces es un caso de descomposición de la expresión. Afortunadamente tengo todo el código para eso en protobuf-net, here - en particular ResolveMethod, que devuelve los valores en la matriz out (después de recorrer cualquier variable capturada, etc.).

Después de hacer ResolveMethod pública (y la eliminación de todo lo anteriorResolveMethod), el código es simplemente:

public static object[] GetParams<T>(this T obj, Expression<Action<T>> action) 
{ 
    Action ignoreThis; 
    object[] args; 
    ProtoClientExtensions.ResolveMethod<T>(action, out ignoreThis, out args); 
    return args; 
} 
+0

(Debo señalar que 'ResolveMethod' también devuelve' MethodInfo', es decir, el hecho de que llamabas a 'Bar') –

+0

(ah, también comenté la línea sobre' RpcUtils', que no importa para esto) –

+0

Gracias Marc, eso está funcionando maravillosamente. Creo que necesito repasar Expressions. – RichK

2

Su acción x => x.Bar(7, "hello") se puede reescribir como

void action(T x) 
{ 
    return x.Bar(7, "hello"); 
} 

Está claro ahora que 7 y "hello" no son los parámetros de la acción, solo x es.

Para obtener acceso a 7 y "hello", necesita un acceso a la expresión, como lo que sugiere @Marc. Sin embargo, no está claro cómo su código debería manejar expresiones más complicadas, como x => 1 + x.Bar(7, x.Baz("hello", x.Quux(Application.Current))).

+0

en la última línea; sí, ese es el truco; el código que cité * intenta * hacer tanto como sea posible sin tener efectos secundarios, pero con el ejemplo presentado ejecutará 'Quux' y' Baz', etc., para tratar de obtener solo valores simples para informar como argumentos. –

+0

Intenté esto (bueno, algo similar) pero al compilador no le gusta el bit 1+, "Sólo asignación, llamada, incremento, etc.". – RichK

+0

@RichK: depende mucho del tipo de 'x.Bar'. Agregar 1 supone que es un 'int', pero su tipo real puede ser diferente. – Vlad

5

Debería ser algo como esto:

public static object[] GetParams<T>(this T obj, Expression<Action<T>> action) 
    { 
     return ((MethodCallExpression) action.Body).Arguments.Cast<ConstantExpression>().Select(e => e.Value).ToArray(); 
    } 

que debe hacer algunas comprobaciones para verificar que nada puede no válida enviado a la acción, ya que no todo va a convertirse a un MethodCallExpression, pero usted debe ser capaz seguir desde allí

+0

si bien es válido para este caso, en la mayoría de los ejemplos reales es más complejo, involucra variables capturadas (y posiblemente múltiples ámbitos de captura anidados), evaluaciones de función/operador, etc. –

+0

@Marc Estoy de acuerdo contigo, respondí manteniéndolo simple porque pensó que aparte de toda la complejidad para obtener los valores que pueda tener, lo que realmente necesita para empezar es saber que necesita pasar una Expresión > y desde allí comenzar a jugar con los diferentes escenarios que podría recibir –

+0

Entonces un excelente punto en una dirección apropiada; p –

Cuestiones relacionadas