Quais são os usos de "using" em C #?

319

O usuário kokos respondeu à maravilhosa pergunta Hidden Features of C # mencionando a usingpalavra - chave. Você pode elaborar sobre isso? Quais são os usos de using?

ubermonkey
fonte
É um C # forma de apoiar o idioma RAII: hackcraft.net/raii
Nemanja Trifunovic
1
Você pode usar para objetos que implementaram a interface IDispose. O uso chamará o método Dispose quando esse objeto estiver fora do escopo. Garante chamar Dispose, mesmo que ocorra alguma exceção. Funciona como uma cláusula finalmente e executa Dispose.
precisa saber é o seguinte

Respostas:

480

O motivo da usingdeclaração é garantir que o objeto seja descartado assim que sair do escopo e não exija código explícito para garantir que isso aconteça.

Como em Entendendo a instrução 'using' em C # (codeproject) e Usando objetos que implementam IDisposable (microsoft) , o compilador C # converte

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

para

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

O C # 8 apresenta uma nova sintaxe, denominada " usando declarações ":

Uma declaração using é uma declaração variável precedida pela palavra-chave using. Diz ao compilador que a variável que está sendo declarada deve ser descartada no final do escopo incluído.

Portanto, o código equivalente acima seria:

using var myRes = new MyResource();
myRes.DoSomething();

E quando o controle sair do escopo que contém (geralmente um método, mas também pode ser um bloco de código), myResserá descartado.

paulwhit
fonte
129
Observe que não é necessariamente uma questão de o objeto ser descartado corretamente , mas mais se ele é descartado em tempo hábil. Objetos implementando IDisposable que se apegam a recursos não gerenciados, como fluxos e identificadores de arquivo, também implementam um finalizador que garante que Dispose seja chamado durante a coleta de lixo. O problema é que o GC pode não acontecer por um tempo relativamente longo. usinggarante que Disposeseja chamado assim que você terminar o objeto.
John Saunders
1
Observe que o código gerado é um pouco diferente quando MyRessourceé uma estrutura. Obviamente, não há teste de nulidade, mas também não há boxe para IDisposable. Uma chamada virtual restrita é emitida.
Romain Verdier
4
Por que ninguém menciona que o uso também é usado para importar espaços para nome?
precisa saber é o seguinte
3
Observe que se você escrever diretamente a segunda versão do código, o resultado não será o mesmo. Se você usar o using, a variável criada dentro dele será somente leitura. Não há como conseguir isso para variáveis ​​locais sem a usinginstrução
Massimiliano Kraus
1
@JohnSaunders Além disso, não é garantido que o finalizador seja chamado.
Pablo H
124

Como muitas pessoas ainda fazem:

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

Eu acho que muitas pessoas ainda não sabem o que você pode fazer:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}
BlackTigerX
fonte
2
É possível usar vários objetos de tipos diferentes em uma única instrução using?
Agnel Kurian
12
@AgnelKurian Não: "CS1044 de erro: Não é possível usar mais de um tipo em um para, usando, fixada ou instrução de declaração"
David Sykes
10
Como isso responde à pergunta?
Liam
Na verdade, eu não sabia que podia escrever dois usando statemens antes de um único bloco de código (os aninharia toda vez).
Kub1x
97

Coisas assim:

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

Isso SqlConnectionserá fechado sem a necessidade de chamar explicitamente a .Close()função, e isso acontecerá mesmo se uma exceção for lançada , sem a necessidade de um try/ catch/ finally.

Joel Coehoorn
fonte
1
e se eu estiver usando um "using" dentro de um método e retornar no meio de um using. Há algum problema?
Francisco_ssb
1
Não há problema. No exemplo aqui, a conexão ainda estará fechada, mesmo se você estiver returnno meio do usingbloco.
Joel Coehoorn
30

usando pode ser usado para chamar IDisposable. Também pode ser usado para tipos de alias.

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;
MagicKat
fonte
21

usando, no sentido de

using (var foo = new Bar())
{
  Baz();
}

Na verdade, é uma abreviação de um bloco try / finalmente. É equivalente ao código:

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

Você observará, é claro, que o primeiro trecho é muito mais conciso que o segundo e também que existem muitos tipos de coisas que você pode querer fazer como limpeza, mesmo que uma exceção seja lançada. Por causa disso, criamos uma classe que chamamos de escopo que permite executar código arbitrário no método Dispose. Portanto, por exemplo, se você tivesse uma propriedade chamada IsWorking que sempre desejou definir como false após tentar executar uma operação, você faria o seguinte:

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

Você pode ler mais sobre nossa solução e como a derivamos aqui .

David Mitchell
fonte
12

A documentação da Microsoft afirma que o uso tem uma função dupla ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), como diretiva e em instruções . Como uma declaração , como foi indicado aqui em outras respostas, a palavra-chave é basicamente açúcar sintático para determinar um escopo para descartar um objeto IDisposable . Como diretiva , é rotineiramente usado para importar espaços e tipos de nomes. Também como diretiva, você pode criar aliases para namespaces e tipos, conforme apontado no livro "C # 5.0 Em poucas palavras: o guia definitivo" ( http://www.amazon.com/5-0-Nutshell-The- Referência-definitiva-ebook / dp / B008E6I1K8), de Joseph e Ben Albahari. Um exemplo:

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

Isso é algo a ser adotado com sabedoria, pois o abuso dessa prática pode prejudicar a clareza do código. Há uma boa explicação sobre aliases de C #, também mencionando prós e contras, em DotNetPearls ( http://www.dotnetperls.com/using-alias ).

Aureliano Buendia
fonte
4
Não vou mentir: eu odeio o uso de usingcomo uma ferramenta de pseudônimo. Me confunde ao ler o código - eu já sei que System.Collectionsexiste e tem a IEnumerable<T>classe. Usar um apelido para chamá-lo de outra coisa ofusca-o para mim. Vejo using FooCollection = IEnumerable<Foo>como uma maneira de fazer os desenvolvedores posteriores lerem o código e pensarem: "O que diabos é FooCollectionisso e por que não há uma classe para isso em algum lugar?" Eu nunca o uso e desencorajaria seu uso. Mas isso pode ser apenas eu.
Ari Roth
1
Adendo: admito que possa haver um uso ocasionalmente, como no seu exemplo em que você o define para definir um delegado. Mas eu argumentaria que são relativamente raros.
Ari Roth
10

Eu usei muito isso no passado para trabalhar com fluxos de entrada e saída. Você pode aninhá-los bem e remover muitos dos problemas em potencial com os quais você costuma se deparar (chamando automaticamente descarte). Por exemplo:

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }
Sam Schutte
fonte
8

Apenas adicionando um pouco de algo que me surpreendeu não apareceu. A característica mais interessante de usar (na minha opinião) é que não importa como você sai do bloco using, ele sempre descartará o objeto. Isso inclui devoluções e exceções.

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

Não importa se a exceção é lançada ou a lista é retornada. O objeto DbContext sempre será descartado.

Pluc
fonte
6

Outro ótimo uso do uso é ao instanciar um diálogo modal.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using
Lucas
fonte
1
Você quis dizer frm.ShowDialog?
UuDdLrLrSs
5

Em conclusão, quando você usa uma variável local de um tipo que implementa IDisposable, sempre , sem exceção, use using1 .

Se você usar IDisposablevariáveis não locais , sempre implemente o IDisposablepadrão .

Duas regras simples, sem exceção 1 . Prevenir o vazamento de recursos de outra forma é uma verdadeira dor no * ss.


1) : a única exceção é - quando você está lidando com exceções. Pode ser menos código para chamar Disposeexplicitamente no finallybloco.

Konrad Rudolph
fonte
5

Você pode usar o espaço para nome alternativo usando o seguinte exemplo:

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

Isso é chamado de diretiva usando alias , como você pode ver, pode ser usado para ocultar referências prolongadas, caso você queira tornar óbvio em seu código o que você está se referindo, por exemplo

LegacyEntities.Account

ao invés de

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

ou simplesmente

Account   // It is not obvious this is a legacy entity
VictorySaber
fonte
4

Curiosamente, você também pode usar o padrão using / IDisposable para outras coisas interessantes (como o outro ponto do modo como o Rhino Mocks o usa). Basicamente, você pode tirar vantagem do fato de que o compilador sempre chamará .Dispose no objeto "usado". Se você tem algo que precisa acontecer após uma determinada operação ... algo que tenha um início e um fim definidos ... você pode simplesmente criar uma classe IDisposable que inicie a operação no construtor e termine no método Dispose.

Isso permite que você use a sintaxe realmente agradável para indicar o início e o fim explícitos da operação. É também assim que o material System.Transactions funciona.

Joel Martinez
fonte
3

Ao usar o ADO.NET, você pode usar o teclado para coisas como seu objeto de conexão ou objeto de leitor. Dessa forma, quando o bloco de código for concluído, ele descartará automaticamente sua conexão.

Joseph Daigle
fonte
2
Eu apenas acrescentaria que o bloco de código nem precisa ser concluído. Um bloco de uso descartará o recurso mesmo no caso de uma exceção não tratada.
harpo 16/09/08
Só para esclarecer ainda mais, é uma maneira de ter certeza que o coletor de lixo cuida de suas atribuições quando você quer que ele, em vez de fazê-lo quando ele quer.
moswald 16/09/08
3
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }
Shiraj Momin
fonte
2

O uso é usado quando você tem um recurso que deseja descartar após o uso.

Por exemplo, se você alocar um recurso de arquivo e precisar usá-lo apenas em uma seção do código para um pouco de leitura ou gravação, usar é útil para descartar o recurso de arquivo assim que terminar.

O recurso que está sendo usado precisa implementar o IDisposable para funcionar corretamente.

Exemplo:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}
Bob Wintemberg
fonte
1

A palavra-chave using define o escopo para o objeto e, em seguida, descarta o objeto quando o escopo estiver completo. Por exemplo.

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

Consulte aqui o artigo MSDN sobre o C # usando a palavra-chave.

David Basarab
fonte
1

Não que seja extremamente importante, mas o uso também pode ser usado para alterar recursos em tempo real. Sim, descartável, como mencionado anteriormente, mas talvez você não queira os recursos que não correspondem aos outros recursos durante o restante de sua execução. Então você quer descartá-lo para que não interfira em outro lugar.


fonte
1

Graças aos comentários abaixo, vou limpar um pouco essa postagem (eu não deveria ter usado as palavras 'coleta de lixo' no momento, desculpas):
Quando você usa, ele chama o método Dispose () no objeto no final do escopo do uso. Portanto, você pode ter um ótimo código de limpeza no seu método Dispose ().
Um marcador aqui que, esperançosamente, talvez consiga esse desmarcado: Se você implementar IDisposable, chame GC.SuppressFinalize () em sua implementação Dispose (), pois caso contrário a coleta de lixo automática tentará aparecer e finalizá-la em algum momento. point, que pelo menos seria um desperdício de recursos se você já tiver Dispose () d.

Grank
fonte
Tem um efeito indireto. Como você descartou o objeto explicitamente, ele não requer finalização e, portanto, pode ser submetido à GC anteriormente.
Kent Boogaart 16/09/08
1

Outro exemplo de uso razoável no qual o objeto é descartado imediatamente:

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}
Brendan Kendrick
fonte
1

Tudo fora dos colchetes é descartado; portanto, é ótimo descartar seus objetos se você não os estiver usando. Isso ocorre porque se você possui um objeto SqlDataAdapter e o está usando apenas uma vez no ciclo de vida do aplicativo, está preenchendo apenas um conjunto de dados e não precisa mais dele, pode usar o código:

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically
milot
fonte
1

A instrução using fornece um mecanismo de conveniência para usar corretamente objetos IDisposable. Como regra, quando você usa um objeto IDisposable, você deve declarar e instancia-lo em uma instrução using. A instrução using chama o método Dispose no objeto da maneira correta e (quando você o usa como mostrado anteriormente) também faz com que o próprio objeto fique fora do escopo assim que Dispose é chamado. Dentro do bloco using, o objeto é somente leitura e não pode ser modificado ou reatribuído.

Isso vem de: aqui

Snowell
fonte
1

Para mim, o nome "using" é um pouco confuso, porque pode ser uma diretiva para importar um Namespace ou uma instrução (como a discutida aqui) para tratamento de erros.

Um nome diferente para o tratamento de erros teria sido bom e talvez um pouco mais óbvio.

Seb
fonte
1

Também pode ser usado para criar escopos, por exemplo:

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}
Siamand
fonte
1

A instrução using diz ao .NET para liberar o objeto especificado no bloco using, uma vez que não é mais necessário. Portanto, você deve usar o bloco 'using' para classes que exigem limpeza após elas, como Tipos System.IO.

deepak samantaray
fonte
1

Existem dois usos da usingpalavra - chave em C # da seguinte maneira.

  1. Como diretiva

    Geralmente, usamos a usingpalavra-chave para adicionar namespaces nos arquivos code-behind e class. Em seguida, disponibiliza todas as classes, interfaces e classes abstratas e seus métodos e propriedades na página atual.

    Exemplo:

    using System.IO;
  2. Como uma declaração

    Essa é outra maneira de usar a usingpalavra - chave em C #. Ela desempenha um papel vital na melhoria do desempenho na Coleta de Lixo.

    A usinginstrução garante que Dispose () seja chamado mesmo que ocorra uma exceção ao criar objetos e chamar métodos, propriedades e assim por diante. Dispose () é um método presente na interface IDisposable que ajuda a implementar a Coleta de Lixo personalizada. Em outras palavras, se estou executando alguma operação de banco de dados (Inserir, Atualizar, Excluir), mas de alguma forma ocorre uma exceção, então aqui a instrução using fecha a conexão automaticamente. Não é necessário chamar explicitamente o método Close () da conexão.

    Outro fator importante é que ele ajuda no pool de conexões. O Pool de Conexão no .NET ajuda a eliminar o fechamento de uma conexão com o banco de dados várias vezes. Ele envia o objeto de conexão a um pool para uso futuro (próxima chamada ao banco de dados). Na próxima vez que uma conexão com o banco de dados for chamada do aplicativo, o pool de conexões buscará os objetos disponíveis no pool. Por isso, ajuda a melhorar o desempenho do aplicativo. Portanto, quando usamos a instrução using, o controlador envia o objeto para o conjunto de conexões automaticamente, não há necessidade de chamar os métodos Close () e Dispose () explicitamente.

    Você pode fazer o mesmo que a instrução using usando o bloco try-catch e chamar o Dispose () dentro do bloco final explicitamente. Mas a instrução using faz as chamadas automaticamente para tornar o código mais limpo e elegante. Dentro do bloco using, o objeto é somente leitura e não pode ser modificado ou reatribuído.

    Exemplo:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    using (SqlConnection conn = new SqlConnection(connString))
    {
          SqlCommand cmd = conn.CreateCommand();
          cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
          conn.Open();
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
             while (dr.Read())
             Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
          }
    }

No código anterior, não estou fechando nenhuma conexão; fechará automaticamente. A usinginstrução chamará conn.Close () automaticamente devido à usinginstrução ( using (SqlConnection conn = new SqlConnection(connString)) e o mesmo para um objeto SqlDataReader. E também, se ocorrer alguma exceção, ela fechará a conexão automaticamente.

Para obter mais informações, consulte Uso e importância do uso em C # .

Chamila Maddumage
fonte
-1

usar como uma declaração chama automaticamente a disposição no objeto especificado. O objeto deve implementar a interface IDisposable. É possível usar vários objetos em uma instrução, desde que sejam do mesmo tipo.

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 finally.

Vazgen Torosyan
fonte
-3

A Cláusula Using é usada para definir o escopo da variável específica. Por exemplo:

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }
Riya Patil
fonte
Isso pode enganar alguém, usando é para descartar objetos. Talvez você esteja confundindo isso com o bloco de código, se você quiser limitar o escopo de uma variável, pode usar um bloco de código aninhado para isso: public static void Main (params string [] args) {{// bloco de código aninhado}}
luiseduardohd