[Pregunta] ¿Cuál es la salida de este programa?

class Program

{

   static void Main(string[] args)

   {

       var arrayAction = new Action[10];

 

       for (var i = 0; i < 10; i++)

       {

           arrayAction[i] = () => Console.Write("{0} ", i);

       }

 

       foreach (var action in arrayAction)

       {

           action();

       }

 

       Console.Read();

   }

}

a) 0 1 2 3 4 5 6 7 8 9

b) 1 2 3 4 5 6 7 8 9 10

c) 0 0 0 0 0 0 0 0 0 0

d) 10 10 10 10 10 10 10 10 10 10

Un saludo.

12 comentarios en “[Pregunta] ¿Cuál es la salida de este programa?”

  1. Sin decir la solución, esta es diferente a:

    static void Main(string[] args)
    {
    var arrayAction = new Action[10];
    for (var i = 0; i < 10; i++) { var j = i; arrayAction[i] = () => Console.Write(“{0} “, j);
    }
    foreach (var action in arrayAction)
    {
    action.Invoke();
    }
    Console.Read();
    }

  2. Realmente en la línea en la que asignas el delegado al Action no le has indicado que el valor i se le debe pasar por argumento, sino que simplemente lo utilizas en el interior.

    Esto hace que simplemente se guarde la referencia y en el momento de la invocación (ya en el segundo bucle), busque el valor de esa variable que después de todas las iteraciones es 10. En en todos las acciones muestra el mismo valor porque todas las Acciones apuntan al mismo espacio de memoria.

    En el caso que he comentado yo, como la variable se ha declarado dentro del primer bucle, esta cada iteración le crea un espacio de memoria diferente y entonces muestra los valores de 0-9.

  3. Pues efectivamente es la D:

    10 10 10 10 10 10 10 10 10 10

    ¿Por qué?

    Tiene que ver con lo que se denominan “closures” o “clausura”

    http://es.wikipedia.org/wiki/Clausura_(inform%C3%A1tica)

    que nos viene a decir más o menos:

    Que las funciones internas tienen acceso real a las variables de la función externa y no a una copia, en este caso la expresión lambda tiene acceso al valor actual de i (10, porque lo hemos ido incrementado en el bucle for) y no a una copia con el valor que tenía i cuando creamos dicha lambda.

    ¿Solución?

    Pues @Xavi Paper lo ha puesto en su código, usar una variable auxiliar que será la copia con el valor actual de i que use la lambda cuando se crea y por lo tanto la salida del programa será:

    0 1 2 3 4 5 6 7 8 9

    Un saludo

  4. Ostias Edu!
    Gracias por el link… aunque como sigan metiendo más syntactic sugar, al final los developers diabéticos van a petar! 😉

  5. Esa es justamente la gracia de los closures! y si no, mirá como se puede crear un tipo a la javascript:

    class Program
    {
    static void Main(string[] args)
    {
    var person = CreatePerson(new{
    FirstName = “Lucas”,
    LastName = “Ontivero”,
    Age = 34
    });

    Console.WriteLine(“Name……. : {0}”, person.GetFullName());
    Console.WriteLine(“IsJuvenile. : {0}”, person.IsJuvenile);

    person.SetFirstName(“Pablo”);
    Console.WriteLine(“Name……. : {0}”, person.GetFullName());

    Console.ReadKey();
    }

    static private dynamic CreatePerson(dynamic cfg)
    {
    var firstName = cfg.FirstName;
    var lastName = cfg.LastName;
    var age = cfg.Age;

    return new{
    GetFullName = new Func(()=> string.Format(“{0} {1}”, firstName, lastName)),
    FirstName = firstName,
    LastName = lastName,
    SetFirstName = new Action
    (fn => firstName= fn),
    SetLastName = new Action
    (ln => lastName = ln),
    IsJuvenile = age < 18 }; }

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *