2010-08-02 18 views
15

Este es mi código de prueba:argumento de tipo 'vacío' no se puede asignar al parámetro de tipo 'System.Action'

class PassingInActionStatement 
{ 
    static void Main(string[] args) 
    { 
     var dsufac = new DoSomethingUsefulForAChange(); 

     dsufac.Do(WriteToConsole); 
     dsufac.Do2(s => WriteToConsoleWithSomethingExtra("Test")); 
     dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); // Does not compile 
    } 

    internal static void WriteToConsole() 
    { 
     Console.WriteLine("Done"); 
    } 

    internal static void WriteToConsoleWithSomethingExtra(String input) 
    { 
     Console.WriteLine(input); 
    } 
} 

internal class DoSomethingUsefulForAChange 
{ 
    internal void Do(Action action) 
    { 
     action(); 
    } 

    internal void Do2(Action<String> action) 
    { 
     action(""); 
    } 
} 

Las 2 primeras llamadas de trabajo, pero me pregunto por qué el tercero no lo hace. No me gusta el código dentro de Do2, ya que parece extraño que tengo tipo de tipo action("") allí para que funcione.

¿Podría alguien explicar las 2 cosas que no entiendo, por favor?

  1. ¿Por qué no puedo escribir la tercera línea de esa manera con llamar Do
  2. ¿Por qué tengo que escribir la acción ("") a fin de conseguir que funcione en Do2
+0

siempre he marcado respuestas que me ayudaron. Si no hay una solución que proporcione algo útil, no la marque hasta que obtenga la respuesta que me ayuda. –

Respuesta

32
dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); 

realidad llama primero a la función (WriteToConsoleWithSomethingExtra("Test")) y luego intenta pasar el resultado a Do. Como no hay resultados (void), no es posible.

lo que realmente quiere decir esto:

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test")); 

La parte interna declara una función que toma nada (el () => bits), que llama WriteToConsoleWithSomethingExtra("Test") cuando se ejecuta. Luego su llamada dsufac.Do recibirá una acción, como espera.

En cuanto a Do2 - que ha declarado como teniendo Action<String>, lo que significa que action es una función que toma un argumento . Tienes que pasarle una cuerda. Esa cadena puede estar vacío, como en el ejemplo action(""), o podría ser aprobada en el exterior, como en algo como esto:

dsufac.Do3(WriteToConsole, "Test"); 

... 

internal void Do3(Action<String> action, String str) 
{ 
    action(str); 
} 
+0

Waw! Eso funciona. Todavía tengo muchos problemas con esas cosas de Acción y Func. ¿Hay algunos tutoriales decentes además de MSDN o libros que pueda sugerir? Marcaré tu respuesta como tal cuando me permita (aparentemente tendré que esperar otros ... minutos). –

+0

Gracias por la actualización extra. –

1
  1. Do espera un Action (es decir, método que toma parámetros y devuelve ningún valor) Por lo tanto, WriteToConsoleWithSomethingExtra no es un ajuste válido: toma un parámetro de cadena.
  2. Do2 acepta un Action<T> (es decir, un método que toma en un parámetro T y no devuelve ningún valor). Por lo tanto, cuando invoca al delegado/acción, debe proporcionar un parámetro de tipo T, aquí String.
3

En su código

dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); 

se interpreta como la siguiente

var variable = WriteToConsoleWithSomethingExtra("Test"); 
dsufac.Do(variable); 

A medida que el tipo de retorno de WriteToConsoleWithSomethingExtra ("Test") es nula, por lo que en realidad no puede pasarlo a dsufac.Do(). Es por eso que no se compila. Sin embargo, para el primero

dsufac.Do(WriteToConsole); 

no está llamando a la función, en lugar está de paso como un grupo de métodos, que luego es conseguir invocada en el método Do() del objeto dsufac.Sin embargo, si desea escribir la tercera línea que el primero uno, puede utilizar

dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test")); 
1

que estaba haciendo algo como esto por un tiempo en una aplicación de Silverlight. Ahora, cuando se ejecuta, parte de ella se rompe.
Esto sucede en una ventana secundaria Silverlight:

(my object context).SaveChanges(() => ChangesSaved()); 

private void ChagngesSaved() 
{ 
    DialogResult = true: // is supposed to close the child window. line gets hit, does not close 
} 
Cuestiones relacionadas