Respostas:
Como vários outros apontaram em geral, isso não é um problema.
O único caso que causará problemas é se você retornar no meio de uma instrução using e adicionalmente retornar a variável using. Mas, novamente, isso também causaria problemas, mesmo que você não voltasse e simplesmente mantivesse uma referência a uma variável.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Tão ruim
Something y;
using ( var x = new Something() ) {
y = x;
}
return
instrução torna o fim do using
bloco inacessível por qualquer caminho de código. O final do using
bloco precisa ser executado para que o objeto possa ser descartado, se necessário.
Está perfeitamente bem.
Você aparentemente está pensando que
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
é traduzido cegamente para:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
O que, reconhecidamente, seria um problema e tornaria a using
afirmação inútil - e é por isso que não é isso que ela faz.
O compilador garante que o objeto seja descartado antes do controle sair do bloco - independentemente de como ele sai do bloco.
É absolutamente bom - não há problema algum. Por que você acredita que está errado?
Uma declaração de uso é apenas açúcar sintático para um bloco try / finalmente, e como Grzenio diz que é bom retornar também de um bloco try.
A expressão de retorno será avaliada, o bloco final será executado e o método retornará.
Isso é totalmente aceitável. A usando instrução garante que o objeto IDisposable seja descartado, não importa o quê.
Do MSDN :
A instrução using garante que Dispose seja chamado mesmo se uma exceção ocorrer enquanto você estiver chamando métodos no objeto. Você pode obter o mesmo resultado colocando o objeto dentro de um bloco try e depois chamando Dispose em um bloco final; de fato, é assim que a instrução using é traduzida pelo compilador.
O código abaixo mostra como using
está funcionando:
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());
}
Resultado:
't1' é criado.
't2' é criado.
't3' é criado.
'Criado a partir de t1, t2, t3' é criado.
't3' é descartado.
't2' é descartado.
't1' é descartado.
Os descartados são chamados após a declaração de retorno, mas antes da saída da função.
Talvez não seja 100% verdade que isso seja aceitável ...
Se você estiver aninhando usos e retornando de dentro de um aninhado, talvez não seja seguro.
Tome 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 um DataTable para ser produzido como CSV. Com o retorno no meio, ele estava gravando todas as linhas no fluxo, mas o csv emitido estava sempre faltando uma linha (ou várias, dependendo do tamanho do buffer). Isso me disse que algo não estava sendo fechado corretamente.
A maneira correta é garantir que todas as utilizações anteriores sejam descartadas 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();
}