Existem efeitos colaterais de retornar de dentro de uma instrução using ()?


125

Retornar um valor de método de dentro de uma instrução using que obtém um DataContext parece sempre funcionar bem , assim:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

Mas eu sempre sinto que eu deveria ser fechar algo antes de eu sair da usando colchetes, por exemplo, através da definição de transação antes a instrução usando, obtê-lo de valor dentro dos colchetes, e depois retornando após os suportes.

Definir e retornar a variável fora dos colchetes usando seria uma prática melhor ou conservaria os recursos de alguma maneira?


1
Pode ser interessante olhar para a IL geral para variantes disso. Eu suspeito que haveria pouca diferença na IL gerada. Normalmente, eu nem me incomodaria em declarar a transação var - basta retornar o resultado da expressão.
Jonesie

Respostas:


164

Não, acho que é mais claro assim. Não se preocupe, Disposeainda será chamado de "saída" - e somente depois que o valor de retorno for totalmente avaliado. Se uma exceção for lançada a qualquer momento (incluindo a avaliação do valor de retorno), Disposetambém será chamada também.

Embora você certamente possa seguir o caminho mais longo, são duas linhas extras que apenas adicionam cruft e contexto extra para acompanhar (mentalmente). De fato, você realmente não precisa da variável local extra - embora possa ser útil em termos de depuração. Você poderia apenas ter:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

Na verdade, posso até ficar tentado a usar a notação de ponto e colocar a Wherecondição dentro de SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}

2
Sine é você @jon, ainda é seguro se uma exceção for lançada dentro do bloco usando?
31410 Dave Archer #

6
sim. usando é simplesmente açúcar sintático para uma tentativa / finalmente construo
Mitch trigo

@ David: Como Mitch diz, está tudo bem - eu atualizei a resposta para fazer com que mais clara :)
Jon Skeet

2
Por que usar OrderByDescending em combinação com SingleOrDefault?
precisa saber é o seguinte

2
@erikkallen: O LINQ não possui um "MaxBy", infelizmente - portanto, você não pode obter a linha com o valor máximo. Para o LINQ to Objects, você pode escrever o seu com bastante facilidade, mas não tenho certeza de uma maneira melhor de fazê-lo neste caso. O que você sugeriria?
precisa

32

Veja isso

Compreendendo a instrução 'using' em C #

O CLR converte seu código em MSIL. E a instrução using é traduzida em uma tentativa e, finalmente, em um bloco. É assim que a instrução using é representada em IL. Uma declaração de uso é traduzida em três partes: aquisição, uso e descarte. O recurso é adquirido primeiro e, em seguida, o uso é incluído em uma instrução try com uma cláusula finally. O objeto é descartado na cláusula Finalmente.


4
Uma visão interessante. Obrigado.
Kangkan

1
Isso traduz a pergunta para: Algum efeito colateral do retorno do bloco de tentativa de uma tentativa finalmente?
Henk Holterman

3

6

Não efeitos colaterais de retornar de dentro de uma using()declaração.

Se torna o código mais legível é outra discussão.


0

Eu acho que é tudo a mesma coisa. Não há nada de ruim no código. A estrutura .NET não se importaria onde o objeto é criado. O que importa é se é referenciado ou não.


-1

Sim, pode haver um efeito colateral. Por exemplo, se você usar a mesma técnica no método de ação do ASP.NET MVC, receberá o seguinte erro: "A instância do ObjectContext foi descartada e não pode mais ser usada para operações que exigem uma conexão"

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}

2
se você definir uma transação fora da instrução using, receberá o mesmo erro. using keyword não está relacionado neste caso.
Costa
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.