2010-08-27 16 views
13

¿Es posible tener un lambda/delegado C# que pueda tomar un número variable de parámetros que se puedan invocar con una invocación dinámica?Parámetros variables en C# Lambda

Todos mis intentos de utilizar la palabra clave 'params' en este contexto han fallado.


UPDATE con CODIGO DE TRABAJO DE ANSWER:

delegate void Foo(params string[] strings); 

static void Main(string[] args)      
{ 
    Foo x = strings => 
    { 
     foreach(string s in strings) 
      Console.WriteLine(s); 
    }; 

    //Added to make it clear how this eventually is used :) 
    Delegate d = x; 

    d.DynamicInvoke(new[]{new string[]{"1", "2", "3"}}); 
} 
+0

¿Puede publicar el código que ha probado hasta ahora para tener una mejor idea de lo que está buscando? –

+0

Creo que está tratando de hacer 'Func func' – tster

Respuesta

15

La razón de que no funciona cuando pasando los argumentos directamente a DynamicInvoke() es porque DynamicInvoke() espera una matriz de objetos, un elemento para cada parámetro del método de destino, y el compilador interpretará una única matriz como la matriz de params en DynamicInvoke() en lugar de un único argumento para el método de destino (a menos que lo lances) como un solo object).

También puede llamar al DynamicInvoke() pasando una matriz que contiene la matriz de parámetros del método de destino. La matriz externa se aceptará como argumento para el parámetro DynamicInvoke()params y la matriz interna se aceptará como la matriz params para el método de destino.

delegate void ParamsDelegate(params object[] args); 

static void Main() 
{ 
    ParamsDelegate paramsDelegate = x => Console.WriteLine(x.Length); 

    paramsDelegate(1,2,3); //output: "3" 
    paramsDelegate();  //output: "0" 

    paramsDelegate.DynamicInvoke((object) new object[]{1,2,3}); //output: "3" 
    paramsDelegate.DynamicInvoke((object) new object[]{}); //output: "0" 

    paramsDelegate.DynamicInvoke(new []{new object[]{1,2,3}}); //output: "3" 
    paramsDelegate.DynamicInvoke(new []{new object[]{}});  //output: "0" 
} 
+0

Me falta algo. ¿Cuál sería el sentido de llamar 'DynamicInvoke' en' ParamsDelegate'? ¿O crees que es solo en caso de que tengas un 'ParamsDelegate' escrito como' Delegate'? –

+0

@wb Actualicé la respuesta con una explicación. –

+0

+1 para el enfoque sin 'DynamicInvoke'. 'DynamicInvoke' es algo que haría todo lo posible para evitar incluso sin benchmarking. Es un poco lento. – nawfal

1

No, pero cualquiera de los parámetros que toma puede ser una matriz.

Sin más detalles, eso es todo lo largo y corto.

0

No, pero con un poco de ayuda, casi se puede fingir:

object[] Params(params object[] args) { return args;} 

// : 

Action<string, object[]> CWL = 
        (format, args) => Console.WriteLine(format, args); 

CWL("{0}, {1}", Params(1,2)); 
+5

Hombre, una vez que Microsoft presentó a los delegados de 'Action' * y' Func' * es como si todo el mundo se olvidó de que en realidad se le permite declarar el suyo también ... –

0

Agregando a la respuesta de la marca, que crearía un método de extensión para limpiar un poco:

static DynamicInvokeParams(this ParamsDelegate delegate, params object[] args) 
{ 
    delegate.DynamicInvoke(new [] {args}); 
} 

y a continuación, sólo tiene que decir:

paramsDelegate.DyanamicInvokeParams(1, 2, 3); 
+0

Pero ¿por qué haría esto cuando podría escribir 'paramsDelegate (1, 2, 3); '? –

+0

Punto razonable; Supongo que el OP probablemente quiera usar DynamicInvoke porque tienen una matriz, por lo que es más probable que sea 'paramsDelegate.DynamicInvokeParams (new [] {1, 2, 3})' que todavía es un poco más agradable. –

0

siento que hay un punto muy importante que no se discute aquí, y eso es todo si ha definido un tipo de delegado que toma un argumento params, no tiene mucho sentido llamar DynamicInvoke en él al. El escenario solo que puedo imaginar en el que esto entraría en juego es si tiene un delegado de su tipo personalizado y lo está pasando como parámetro a algún método que acepta un argumento Delegate y llama al DynamicInvoke en que.

Pero vamos a ver este código en la actualización de la OP:

delegate void Foo(params string[] strings); 

static void Main(string[] args)      
{ 
    Foo x = strings => 
    { 
     foreach(string s in strings) 
      Console.WriteLine(s); 
    }; 

    x.DynamicInvoke(new[]{new string[]{"1", "2", "3"}}); 
} 

La llamada DynamicInvoke anterior es totalmente superfluo. Sería mucho más sensato que lea la última línea:

x("1", "2", "3"); 
+0

Sí, en este caso simplificado sería inútil, pero en el caso de implementación real no es como se convierte en un delegado general que se llama en otro lugar. Actualizaré mi publicación para hacer esto más obvio. – iam

+0

@wb: OK, en ese caso entiendo tu necesidad de resolver esto. Voy a actualizar mi respuesta con una explicación que creo que te ayudará. –

+0

Todavía estoy un poco inseguro de por qué se necesita la parte ..new [] {... aunque debo añadir. – iam

Cuestiones relacionadas