retornando no meio de um bloco usando
-
20-08-2019 - |
Pergunta
Algo como:
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
Eu acredito que não é um lugar adequado para uma instrução de retorno, não é?
Solução
Como vários outros apontaram, em geral, isso não é um problema.
O único caso que fará com que você emite é se você voltar no meio de uma instrução using e, adicionalmente, devolver o no uso variável. Mas, novamente, isso também faria com que você emite, mesmo se você não voltar e simplesmente manteve uma referência a uma variável.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Assim como mau
Something y;
using ( var x = new Something() ) {
y = x;
}
Outras dicas
É perfeitamente bem.
Você está aparentemente pensando que
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
é cegamente traduzido em:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
O que, na verdade, seria um problema, e gostaria de fazer a declaração using
bastante inútil --- que é por isso que é não o que faz.
O compilador garante que o objeto é descartado antes das folhas de controle do bloco - independentemente de como ele deixa o bloco
.É absolutamente bem - não há problema em tudo. Por que você acredita que é errado?
A instrução using é apenas açúcar sintático para um try / finally bloco, e como Grzenio diz que é bom para o retorno de um bloco try também.
A expressão de retorno serão avaliados, em seguida, o bloco finally será executado, em seguida, o método irá retornar.
Isto irá funcionar perfeitamente bem, assim como o retorno no meio da try{}finally{}
Isso é totalmente aceitável. A usando declaração garante o objeto IDisposable serão eliminados não importa o que.
A partir MSDN :
Os utilizando garante declaração que Dispose é chamado, mesmo se uma exceção ocorre enquanto você está chamando métodos no objeto. Você pode conseguir o mesmo resultado, colocando o objeto dentro de um bloco try e, em seguida, chamar Dispose em um bloco, finalmente; Na verdade, esta é a forma como a declaração usando é traduzido pelo compilador.
O código abaixo mostra como using
está trabalhando:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Output:
't1' é criado.
'T2' é criado.
'T3' é criado.
'Criado a partir de T1, T2, T3' é criado.
'T3' é descartado.
'T2' é descartado.
'T1' é descartado.
O disposto são chamados após a instrução de retorno, mas antes da saída da função.
Talvez não seja 100% verdade que isso é aceitável ...
Se acontecer de você ser usings nidificação e retornando a partir de dentro um aninhado, ele pode não ser seguro.
Leve isso como um exemplo:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
Eu estava passando em uma DataTable a ser emitida como CSV. Com o retorno no meio, ele estava escrevendo todas as linhas para o fluxo, mas o CSV emitido estava sempre faltando uma linha (ou múltiplos, dependendo do tamanho do buffer). Este disse-me que algo não estava sendo fechada corretamente.
A maneira correta é certificar-se todos os usings anteriores são eliminados corretamente:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}