De onde vêm os marcadores de gravadoras em refletor e como decifrá -los?
-
21-09-2019 - |
Pergunta
Estou tentando entender um método usando o recurso de desmontagem do refletor. Como qualquer pessoa que seja usada essa ferramenta saberá, certos código são exibidos com etiquetas C# que foram (presumivelmente) não usadas na fonte original.
No método de 110 linhas que estou vendo, existem 11 declarações de etiquetas. Exemplos aleatórios de snippet:
Label_0076:
if (enumerator.MoveNext())
{
goto Label_008F;
}
if (!base.IsValid)
{
return;
}
goto Label_0219;
Label_0087:
num = 0;
goto Label_01CB;
Label_01CB:
if (num < entityArray.Length)
{
goto Label_0194;
}
goto Label_01AE;
Label_01F3:
num++;
goto Label_01CB;
Que tipo de código faz com que o refletor exiba esses rótulos em todos os lugares e por que não pode desmontá -los?
Existe uma boa técnica para decifrá -los?
Solução
Você está olhando para o código gerado pelo compilador. O compilador não o respeita. Não mesmo. Isso também não me respeita ou mais ninguém. Ele analisa nosso código, zomba de nós e o reescreve para executar da maneira mais eficiente possível.
Aninhadas se declarações, recursão, "rendimento" s, declarações de caso e outros atalhos de código resultarão em código de aparência estranha. E se você estiver usando lambdas com muitos gabinetes, bem, não espere que seja bonito.
Em qualquer lugar, qualquer chance de o compilador reescrever seu código para fazê -lo funcionar mais rapidamente. Portanto, não há um "tipo de código" que causará isso. O Reflector faz o possível para desmontar, mas não pode adivinhar o código original do autor de sua versão reescrita. Faz o seu melhor (que às vezes está incorreto!) Para traduzir IL em alguma forma de código aceitável.
Se você está tendo dificuldade em decifrá -lo, poderá editar manualmente o código para inline o Goto que só é chamado uma vez e refator os Goto's que são chamados mais de uma vez em chamadas de método. Outra alternativa é desmontar em outro idioma. O código que traduz IL em idiomas de nível superior não é o mesmo. O decompilador C ++/CLI pode fazer um trabalho melhor para você e ainda ser semelhante o suficiente (encontre/substitua -> com.) Para ser compreensível.
Realmente não há uma bala de prata para isso; Pelo menos até que alguém escreve um plugin de desmontador melhor.
Outras dicas
Na verdade, o compilador C# não faz muita otimização - deixa isso para o compilador JIT (ou NGEN). Como tal, o IL que gera é bastante consistente e previsível, e é por isso que ferramentas como o refletor são capazes de descompilar o IL de maneira tão eficaz. Uma situação em que o compilador transforma seu código está em um iterador método. O método que você está olhando provavelmente continha algo como:
foreach(var x in something)
if(x.IsValid)
yield return x;
Como a transformação do iterador pode ser bastante complexa, o refletor não pode realmente lidar com isso. Para se familiarizar com o que procurar, escreva seus próprios métodos de iterador e execute -os através do refletor para ver que tipo de IL é gerado com base no seu código C#. Então você saberá o que procurar.