Pregunta

string [] files = new string[2];
files[0] = "ThinkFarAhead.Example.Settings.Configuration_Local.xml";
files[1] = "ThinkFarAhead.Example.Settings.Configuration_Global.xml";

//Resharper complains this is an "access to modified closure"
for (int i = 0; i < files.Length; i++ )
{
    // Resharper disable AccessToModifiedClosure
    if(Array.Exists(Assembly.GetExecutingAssembly().GetManifestResourceNames(),
    delegate(string name) { return name.Equals(files[i]); }))
         return Assembly.GetExecutingAssembly().GetManifestResourceStream(files[i]);
    // ReSharper restore AccessToModifiedClosure
}

Lo anterior parece funcionar bien, aunque ReSharper se queja de que este es el acceso al cierre modificado. ¿Alguien puede arrojar luz sobre esto?

(este tema continúa aquí )

¿Fue útil?

Solución

En este caso, está bien, ya que en realidad está ejecutando el delegado dentro de el bucle.

Si guardara el delegado y lo usara más tarde, sin embargo, encontrará que todos los delegados lanzarán excepciones cuando intenten acceder a los archivos [i]: están capturando la variable i en lugar de su valor en el momento de la creación de delegados.

En resumen, es algo que debes tener en cuenta como una trampa para potencial , pero en este caso no te hace daño.

Consulte la parte inferior de esta página para ver un ejemplo más complejo donde los resultados son contraintuitivos.

Otros consejos

Sé que esta es una vieja pregunta, pero recientemente he estado estudiando cierres y pensé que una muestra de código podría ser útil. Detrás de escena, el compilador está generando una clase que representa un cierre léxico para su llamada de función. Probablemente se parece a algo como:

private sealed class Closure
{
    public string[] files;
    public int i;

    public bool YourAnonymousMethod(string name)
    {
        return name.Equals(this.files[this.i]);
    }
}

Como se mencionó anteriormente, su función funciona porque los predicados se invocan inmediatamente después de la creación. El compilador generará algo como:

private string Works()
{
    var closure = new Closure();

    closure.files = new string[3];
    closure.files[0] = "notfoo";
    closure.files[1] = "bar";
    closure.files[2] = "notbaz";

    var arrayToSearch = new string[] { "foo", "bar", "baz" };

    //this works, because the predicates are being executed during the loop
    for (closure.i = 0; closure.i < closure.files.Length; closure.i++)
    {
        if (Array.Exists(arrayToSearch, closure.YourAnonymousMethod))
            return closure.files[closure.i];
    }

    return null;
}

Por otro lado, si almacenara y luego invocara los predicados, vería que cada llamada a los predicados realmente llamaría al mismo método en la misma instancia de la clase de cierre y, por lo tanto, utilizaría mismo valor para i.

" archivos " es una variable externa capturada porque ha sido capturada por la función de delegado anónimo. Su vida útil se extiende por la función de delegado anónimo.

  

Variables externas capturadas   Cuando una función anónima hace referencia a una variable externa, se dice que la variable externa ha sido capturada por la función anónima. Normalmente, la vida útil de una variable local se limita a la ejecución del bloque o la declaración con la que está asociada (variables locales). Sin embargo, la vida útil de una variable externa capturada se extiende al menos hasta que el delegado o el árbol de expresiones creado a partir de la función anónima se convierta en elegible para la recolección de basura.

https: / /docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#outer-variables

  

Cuando una variable anónima captura una variable local o un parámetro de valor, la variable o parámetro local ya no se considera una variable fija (variables fijas y móviles), sino que se considera una variable móvil. Por lo tanto, cualquier código inseguro que tome la dirección de una variable externa capturada primero debe usar la instrucción fija para corregir la variable.   Tenga en cuenta que, a diferencia de una variable no capturada, una variable local capturada puede exponerse simultáneamente a múltiples hilos de ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top