Resposta ao Desafio da Semana #4 [Crash - Tratamento de Exceções em C#/VB.NET]
Por: Roberto Alexis Farah
Oi pessoal!
Eis a resposta do Desafio da Semana #4.
https://blogs.technet.com/latam/archive/2006/05/12/428158.aspx
PROBLEMA
O comportamento da aplicação pode parecer estranho mas ele é coerente!
Note que o bloco finally deve sempre ser executado. E, de fato, é usado principalmente para liberar recursos reservados no bloco try, independente de uma exceção ter sido lançada ou não.
Portanto, sabemos que o bloco finally deve ser sempre executado e está sendo. (há documentação no MSDN sobre isso)
Pois bem, porque o valor da variável não mudou isso não significa que há um problema no compilador C#.
Afinal, a lógica da aplicação é para retornar o valor da variável “a” dentro do bloco try sem a interferência da execução do bloco finally.
Se uma exceção fosse disparada antes do return seria mais claro ver a necessidade do finally ser executado.
Mas, você poderia perguntar: e se o valor retornado fosse o valor do bloco finally?
Se isso ocorresse seria incoerente pois seria o mesmo que usar esse bloco de código:
public static string makeStrangeStuff()
{
StrangeStuff.a = "Anomaly";
try
{
}
finally
{
StrangeStuff.a = "Greater Anomaly";
}
return StrangeStuff.a;
}
Note que no bloco de código acima temos uma lógica diferente. No código acima o return StrangeStuff.a vem depois do bloco finally, logo, é esperado que o retorno seja o conteúdo do bloco finally!
De volta ao código original, se analisarmos o metadata temos:
public static string makeStrangeStuff()
{
string CS$1$0000;
StrangeStuff.a = "Anomaly";
try
{
CS$1$0000 = StrangeStuff.a;
}
finally
{
StrangeStuff.a = "Greater Anomaly";
}
return CS$1$0000;
}
Uma variável interna é criada para produzir o resultado atual, entretanto, se você mudar o código de modo a por o return StrangeStuff.a após o finally e usar ILDasm para ver o resultado você vai notar que o código gerado não mudou:
public static string makeStrangeStuff()
{
StrangeStuff.a = "Anomaly";
try
{
}
finally
{
StrangeStuff.a = "Greater Anomaly";
}
return StrangeStuff.a;
}
Nesse caso não há necessidade do compilador criar uma variável interna, a execução é direta.
Em relação ao código original é recomendado se usar saída de métodos (o return no caso) fora do bloco try pois, como vocês viram, pontos de saída dentro do bloco try deixam o código mais difícil de entender, menos legível.
Outro exemplo para ilustrar:
static private DateTime Test()
{
try
{
return DateTime.Now; // ß Valor retornado não vai mudar após o finally.
}
finally
{
Thread.Sleep(80000);
}
}
Infelizmente essa semana não tive tempo de preparar o próximo desafio. L
Mas até semana que vem vou fazê-lo e publicá-lo.
Até lá.