Pergunta

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
}

A descrição acima parece funcionar bem, embora ReSharper reclama que este é "o acesso ao encerramento modificado". Qualquer um pode lançar luz sobre isso?

(este tema continuou aqui )

Foi útil?

Solução

Neste caso, não há problema, desde que você está realmente executar o delegado em do loop.

Se você estava salvando o delegado e usá-lo mais tarde, no entanto, você acharia que todos os delegados iria lançar exceções ao tentar acessar arquivos [i] - eles estão capturando o variável i em vez de seu valor no momento da criação delegados.

Em suma, é algo para estar ciente de como um potencial armadilha, mas neste caso ele não machucá-lo.

Veja o fundo desta página para um exemplo mais complexo, onde os resultados são contra-intuitivo.

Outras dicas

Eu sei que isto é uma questão de idade, mas eu estive recentemente estudando fechamentos e achei um exemplo de código pode ser útil. Nos bastidores, o compilador está gerando uma classe que representa um fechamento lexical para sua chamada de função. Provavelmente é 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 mencionado acima, a função funciona porque os predicados são invocados imediatamente após a criação. O compilador irá gerar 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 outro lado, se você fosse para armazenar e depois invocar o predicados, você veria que cada chamada para os predicados seria realmente chamar o mesmo método na mesma instância da classe encerramento e, portanto, seria usar o mesmo valor para i.

"arquivos" é um capturado variável externa porque ele foi capturado pela função de delegado anônimo. Sua vida útil é estendida pela função de delegado anônimo.

variáveis ??externas Captured Quando uma variável externa é referenciado por uma função anónimo, a variável exterior é dito ter sido capturado pela função anónimo. Normalmente, o tempo de vida de uma variável local é limitado a execução do bloco ou declaração com o qual está associado (variáveis ??locais). No entanto, o tempo de vida de uma variável externa capturado é estendida pelo menos até que a árvore delegado ou expressão criada a partir da função anônima torna-se elegível para coleta de lixo.

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

Quando uma variável local ou um parâmetro valor é capturado por uma função anônima, a variável local ou parâmetro não é mais considerado como uma variável fixa (fixo e variáveis ??móveis), mas em vez disso é considerado uma variável móvel. Assim, qualquer código inseguro que leva o endereço de uma variável externa capturado deve primeiro usar a instrução fixo para corrigir a variável. Note-se que ao contrário de uma variável uncaptured, uma variável local capturada pode ser simultaneamente exposto a vários threads de execução.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top