2009-10-28 16 views
13

Esto no es un juguete de Calling a method with ref or out parameters from an anonymous method¿Por qué no se permite un parámetro de salida dentro de un método anónimo?

Me pregunto por qué cabo parámetros no están permitidos dentro de los métodos anónimos. No permitir ref parámetros tiene más sentido para mí, pero el fuera de los parámetros, no tanto.

¿Cuáles son sus pensamientos sobre este

+0

Me pregunto POR QUÉ pasarás un tipo anónimo fuera del cuerpo de un método, a menos que quieras aprender la alegría que es Reflexión. – Will

+0

¿Responde esta respuesta en la pregunta del enlace original lo suficiente? http://stackoverflow.com/questions/801147/scope-of-anonymous-methods/801563#801563 –

+1

@Will: Esto no tiene nada que ver con los tipos anónimos. – SLaks

Respuesta

28

De alguna manera esto es una víctima. Out parámetros son ref parámetros. Simplemente hay un atributo adicional en el valor que usa el lenguaje C#. La razón para rechazarlos es exactamente igual que los parámetros ref.

El problema aquí se origina con el efecto de usar un valor declarado fuera del método anónimo dentro del método anónimo. Al hacerlo, capturará el valor dentro de la lambda y, por necesidad, extenderá arbitrariamente su duración más allá de la función actual. Esto no es compatible con los parámetros out que tienen una vida útil fija.

Imagine por ejemplo que el parámetro out se refería a una variable local en la pila. La lambda puede ejecutarse en cualquier punto arbitrario en el futuro y, por lo tanto, podría ejecutarse cuando ese marco de pila ya no sea válido. ¿Qué significaría entonces el parámetro out?

+1

+1 Había empezado a escribir un ejemplo similar al último párrafo. Gracias por salvarme la molestia :) –

+0

El segundo párrafo encendió la bombilla. Gracias @JaredPar! –

+0

¿Pero no se aplicaría eso a cualquier otro tipo de variable? Quiero decir, ¿y si utilizo una variable dentro de una expresión lambda que se encuentra en la pila, simplemente acceda a un campo? Si la expresión lambda se ejecuta cuando la pila ya no es válida, ¿no se habría recopilado el objeto? Si no es así, ¿cuándo recogerá el recolector de basura ese objeto? –

6

Esto es básicamente que ver con el hecho de que los parámetros de un delegado expresiones anónimas/lambda son las variables capturadas y captura de ref/out variables que no tiene ningún sentido en C#/CLR, ya que requeriría ref/outcampos internamente. Además, tenga en cuenta que emparejo estas dos palabras clave porque son efectivamente las mismas.

Si quiere una explicación completa, Eric Lippert discussed this design point in detail en su blog. (Ver los párrafos cerca de la parte inferior en particular.)

1

La única diferencia entre out y ref parámetros es que un parámetro out tendrá un token de [out] aplicada a ella. Son lo mismo en lo que respecta al CLR. Para ejecutarlo, el compilador debería generar refcampos, que no son compatibles.

Si lo piensas bien, te darás cuenta de que no tiene sentido permitir que un método anónimo use un parámetro out.

¿Cuál sería el siguiente código?

static Func<object, object> Mess(out object param) { 
    param = "Original"; 
    return i => param = i; 
} 
static Func<object, object> MessCaller() { 
    object local; 
    return Mess(out local); 
} 
static vouid Main() { 
    Console.WriteLine(MessCaller()("New")); 
    //The local variable that the lambda expression writes to doesn't exist anymore. 
} 
+1

El atributo 'OutAttribute' no se aplica a los parámetros' out' en C#. 'OutAttribute' es un atributo personalizado que se considera al ordenar cosas. Los parámetros 'out' son anotados por otro token de metadatos (' [out] in IL'). Puede verificar este hecho consultando los atributos de un 'ParameterInfo' declarado como' out' en el código C#. No hay '[OutAttribute] 'allí. –

+0

Solucionado; gracias. – SLaks

1

me encontré con este dilema, mientras que el desarrollo de un código de gestión de errores. Quería pasar una referencia (salida) a un mensaje de error que se registraría. Esto le dio a mis métodos anónimos la posibilidad de realizar múltiples comprobaciones, cada una configurando el mensaje de error según sea necesario.

Terminé escribiendo un nuevo contenedor para el método anónimo que funcionaba de manera diferente.Pero lo que pensé que podría ser de algún valor para alguien, es que simplemente podría haber hecho un método privado que tuviera un parámetro de salida, y haya definido un delegado, y haya hecho que mi código lo use. Espero que esto ayude/inspire a alguien.

protected delegate void OutStringDelegate(int divider, out string errorText); 
    protected void codeWrapper(int divider, OutStringDelegate del) 
    { 
     string ErrorMessage = "An Error Occurred."; 

     try 
     { 
      del(divider, out ErrorMessage); 
     } 
     catch 
     { 
      LogError(ErrorMessage); 
     } 
    } 
    public void UseWrapper(int input) 
    { 
     codeWrapper(input, codeToCall); 
    } 
    private int somePrivateValue = 0; 
    private void codeToCall(int divider, out string errorMessage) 
    { 
     errorMessage = "Nice Error Message here!"; 
     somePrivateValue = 1/divider; // call me with zero to cause error. 
    } 
    private void LogError(string msg) 
    { 
     Console.WriteLine(msg); 
    } 
Cuestiones relacionadas