¿Cuáles son los usos de "usar" en C #?

319

El usuario kokos respondió la maravillosa pregunta de Características ocultas de C # mencionando la usingpalabra clave. Puedes profundizar sobre eso? ¿Para qué sirven using?

ubermonkey
fuente
Es una forma C # de apoyar el lenguaje RAII: hackcraft.net/raii
Nemanja Trifunovic
1
Puede usar para objetos que tienen implementada la interfaz IDispose. El uso llamará al método Dispose cuando ese objeto esté fuera de alcance. Garantiza llamar a Dispose incluso si se produce alguna excepción. Funciona como una cláusula finalmente y ejecuta Dispose.
CharithJ

Respuestas:

480

El motivo de la usingdeclaración es garantizar que el objeto se elimine tan pronto como salga del alcance, y no requiere un código explícito para garantizar que esto suceda.

Al igual que en Comprender la instrucción 'using' en C # (proyecto de código) y Usar objetos que implementan IDisposable (microsoft) , el compilador de C # convierte

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

a

{ // 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();
    }
}

C # 8 presenta una nueva sintaxis, llamada " usando declaraciones ":

Una declaración de uso es una declaración variable precedida por la palabra clave de uso. Le dice al compilador que la variable que se declara debe eliminarse al final del ámbito de inclusión.

Entonces el código equivalente de arriba sería:

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

Y cuando el control abandone el ámbito de contención (generalmente un método, pero también puede ser un bloque de código), myResse eliminará.

Paulwhit
fuente
129129
Tenga en cuenta que no se trata necesariamente de que el objeto se elimine correctamente , sino más bien de si se elimina de manera oportuna. Los objetos que implementan IDisposable que retienen recursos no administrados, como secuencias y identificadores de archivos, también implementarán un finalizador que asegurará que se llame a Dispose durante la recolección de basura. El problema es que GC podría no suceder por un tiempo relativamente largo. usingse asegura de que Disposese llame una vez que haya terminado con el objeto.
John Saunders
1
Tenga en cuenta que el código generado es un poco diferente cuando MyRessourcees una estructura. Obviamente no hay prueba de nulidad, pero tampoco hay boxeo IDisposable. Se emite una llamada virtual restringida.
Romain Verdier
44
¿Por qué nadie menciona que usar también se usa para importar espacios de nombres?
Kyle Delaney el
3
Tenga en cuenta que si escribe directamente la segunda versión del código, el resultado no es el mismo. Si usa el using, la variable construida dentro es de solo lectura. No hay forma de lograr esto para las variables locales sin la usingdeclaración.
Massimiliano Kraus
1
@JohnSaunders Además, no se garantiza que se llame al finalizador.
Pablo H
124

Como mucha gente todavía lo hace:

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

Supongo que mucha gente todavía no sabe que puedes hacer:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}
BlackTigerX
fuente
2
¿Es posible usar múltiples objetos de diferentes tipos en una sola declaración usando?
Agnel Kurian
12
@AgnelKurian No: "error CS1044: no se puede usar más de un tipo en una declaración de declaración de uso, fijo o declaración"
David Sykes
10
¿Cómo responde esto a la pregunta?
Liam
En realidad, no sabía que podía escribir dos usando statemens antes de un solo bloque de código (los anidaría cada vez).
kub1x
97

Cosas como esta:

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

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

Esto SqlConnectionse cerrará sin necesidad de llamar explícitamente a la .Close()función, y esto sucederá incluso si se produce una excepción , sin la necesidad de un try/ catch/ finally.

Joel Coehoorn
fuente
1
¿Qué pasa si estoy usando un "uso" dentro de un método, y vuelvo en medio de un uso? ¿Hay algún problema?
francisco_ssb
1
No hay problema. En el ejemplo aquí, la conexión seguirá cerrada, incluso si usted está returnen el medio del usingbloque.
Joel Coehoorn
30

usando se puede usar para llamar a IDisposable. También se puede usar para tipos de alias.

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

utilizando, en el sentido de

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

En realidad es una forma abreviada de un intento / finalmente bloquear. Es equivalente al código:

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

Notarás, por supuesto, que el primer fragmento es mucho más conciso que el segundo y también que hay muchos tipos de cosas que quizás quieras hacer como limpieza, incluso si se lanza una excepción. Debido a esto, hemos creado una clase que llamamos Scope que le permite ejecutar código arbitrario en el método Dispose. Entonces, por ejemplo, si tuviera una propiedad llamada IsWorking que siempre quiso establecer en falso después de intentar realizar una operación, lo haría así:

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

Puede leer más sobre nuestra solución y cómo la derivamos aquí .

David Mitchell
fuente
12

La documentación de Microsoft indica que usar tiene una doble función ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), tanto como directiva como en declaraciones . Como una declaración , como se señaló aquí en otras respuestas, la palabra clave es básicamente azúcar sintáctica para determinar el alcance para disponer de un objeto desechable ID . Como directiva , se usa habitualmente para importar espacios de nombres y tipos. También como directiva, puede crear alias para espacios de nombres y tipos, como se señala en el libro "C # 5.0 In a Nutshell: The Definitive Guide" ( http://www.amazon.com/5-0-Nutshell-The- Libro de referencia definitivo / dp / B008E6I1K8), de Joseph y Ben Albahari. Un ejemplo:

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;
        }
    }
}

Esto es algo para adoptar sabiamente, ya que el abuso de esta práctica puede dañar la claridad del código. Hay una buena explicación sobre los alias de C #, que también menciona los pros y los contras, en DotNetPearls ( http://www.dotnetperls.com/using-alias ).

Aureliano Buendia
fuente
44
No voy a mentir: odio el uso usingcomo una herramienta de alias. Me confunde al leer el código: ya sé que System.Collectionsexiste y que tiene la IEnumerable<T>clase. Usar un alias para llamarlo de otra manera lo ofusca. Veo using FooCollection = IEnumerable<Foo>como una forma de hacer que los desarrolladores posteriores lean el código y piensen: "¿Qué demonios es FooCollectiony por qué no hay una clase para eso en alguna parte?" Nunca lo uso y desalentaría su uso. Pero eso podría ser solo yo.
Ari Roth
1
Anexo: Reconoceré que podría ser útil ocasionalmente, como en su ejemplo donde lo usa para definir un delegado. Pero diría que son relativamente raros.
Ari Roth
10

Lo he usado mucho en el pasado para trabajar con flujos de entrada y salida. Puede anidarlos muy bien y elimina muchos de los problemas potenciales con los que generalmente se encuentra (llamando automáticamente a dispose). Por ejemplo:

        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
fuente
8

Simplemente agregué un pequeño detalle que me sorprendió no surgió. La característica más interesante del uso (en mi opinión) es que no importa cómo salga del bloque de uso, siempre eliminará el objeto. Esto incluye devoluciones y excepciones.

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

No importa si se lanza la excepción o si se devuelve la lista. El objeto DbContext siempre se eliminará.

Pluc
fuente
6

Otro gran uso del uso es cuando se crea una instancia de un diálogo modal.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using
Lucas
fuente
1
¿Quiso decir frm.ShowDialog?
UuDdLrLrSs
5

En conclusión, cuando usa una variable local de un tipo que implementa IDisposable, siempre , sin excepción, use using1 .

Si usa IDisposablevariables no locales , siempre implemente el IDisposablepatrón .

Dos reglas simples, sin excepción 1 . La prevención de fugas de recursos de lo contrario es un verdadero dolor en el * ss.


1) : La única excepción es: cuando maneja excepciones. Entonces podría ser menos código para llamar Disposeexplícitamente en el finallybloque.

Konrad Rudolph
fuente
5

Puede utilizar el espacio de nombres de alias mediante el siguiente ejemplo:

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

Esto se llama una directiva de uso de alias , como puede ver, se puede usar para ocultar referencias largas en caso de que desee hacer obvio en su código a qué se refiere, por ejemplo

LegacyEntities.Account

en vez de

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

o simplemente

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

Curiosamente, también puede usar el patrón de uso / IDisposable para otras cosas interesantes (como el otro punto de la forma en que Rhino Mocks lo usa). Básicamente, puede aprovechar el hecho de que el compilador siempre llamará a .Dispose en el objeto "usado". Si tiene algo que debe suceder después de una determinada operación ... algo que tiene un inicio y un final definidos ... entonces simplemente puede hacer una clase IDisposable que comience la operación en el constructor y luego termine en el método Dispose.

Esto le permite utilizar la sintaxis de uso realmente agradable para denotar el inicio y el final explícitos de dicha operación. Así es también como funciona el material System.Transactions.

Joel Martinez
fuente
3

Cuando use ADO.NET, puede usar el trabajo de teclado para cosas como su objeto de conexión u objeto lector. De esa manera, cuando el bloque de código se complete, eliminará automáticamente su conexión.

Joseph Daigle
fuente
2
Solo agregaría que el bloque de código ni siquiera tiene que completarse. Un bloque que usa eliminará el recurso incluso en el caso de una excepción no controlada.
harpo
Solo para aclarar más, es una forma de asegurarse de que el recolector de basura se encargue de sus asignaciones cuando lo desee, en lugar de hacerlo cuando lo desee.
moswald
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
fuente
2

El uso se utiliza cuando tiene un recurso que desea eliminar después de que se haya utilizado.

Por ejemplo, si asigna un recurso de archivo y solo necesita usarlo en una sección de código para leer o escribir un poco, usarlo es útil para deshacerse del recurso de archivo tan pronto como termine.

El recurso que se utiliza debe implementar IDisposable para que funcione correctamente.

Ejemplo:

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

La palabra clave using define el alcance del objeto y luego desecha el objeto cuando se completa el alcance. Por ejemplo.

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

Consulte aquí el artículo de MSDN sobre C # usando la palabra clave.

David Basarab
fuente
1

No es que sea extremadamente importante, pero el uso también se puede usar para cambiar recursos sobre la marcha. Sí, desechable como se mencionó anteriormente, pero quizás específicamente no desea que los recursos no coincidan con otros recursos durante el resto de su ejecución. Por lo tanto, debe deshacerse de él para que no interfiera en otro lugar.


fuente
1

Gracias a los comentarios a continuación, limpiaré un poco esta publicación (no debería haber usado las palabras 'recolección de basura' en ese momento, disculpas):
cuando use el uso, llamará al método Dispose () en el objeto al final del alcance del uso. Por lo tanto, puede tener un código de limpieza bastante bueno en su método Dispose ().
Una viñeta aquí que con suerte tal vez no se marque: si implementa IDisposable, asegúrese de llamar a GC.SuppressFinalize () en su implementación Dispose (), ya que de lo contrario la recolección automática de basura intentará aparecer y finalizarla en algún momento punto, que al menos sería un desperdicio de recursos si ya ha dispuesto () d de él.

Grank
fuente
Tiene un efecto indirecto. Debido a que ha eliminado el objeto explícitamente, no requiere finalización y, por lo tanto, puede ser GC'd antes.
Kent Boogaart
1

Otro ejemplo de uso razonable en el que el objeto se elimina inmediatamente:

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
fuente
1

Todo lo que esté fuera de los corchetes se desecha, por lo que es excelente deshacerse de los objetos si no los está utilizando. Esto es así porque si tiene un objeto SqlDataAdapter y lo está usando solo una vez en el ciclo de vida de la aplicación y está llenando solo un conjunto de datos y ya no lo necesita, puede usar el código:

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

La instrucción de uso proporciona un mecanismo de conveniencia para usar correctamente los objetos IDisposable. Como regla general, cuando usa un objeto IDisposable, debe declararlo e instanciarlo en una declaración de uso. La instrucción using llama al método Dispose en el objeto de la manera correcta y (cuando lo usa como se muestra anteriormente) también hace que el objeto se salga del alcance tan pronto como se llame a Dispose. Dentro del bloque de uso, el objeto es de solo lectura y no se puede modificar ni reasignar.

Esto viene de: aquí

Snowell
fuente
1

Para mí, el nombre "usar" es un poco confuso, porque puede ser una directiva para importar un espacio de nombres o una declaración (como la que se analiza aquí) para el manejo de errores.

Un nombre diferente para el manejo de errores hubiera sido bueno, y tal vez uno de alguna manera más obvio.

Seb
fuente
1

También se puede usar para crear ámbitos por ejemplo:

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
fuente
1

La instrucción de uso le dice a .NET que libere el objeto especificado en el bloque de uso una vez que ya no sea necesario. Por lo tanto, debe usar el bloque 'usar' para las clases que requieren limpieza después de ellas, como los Tipos System.IO.

deepak samantaray
fuente
1

Hay dos usos de la usingpalabra clave en C # de la siguiente manera.

  1. Como directiva

    Generalmente usamos la usingpalabra clave para agregar espacios de nombres en archivos de clase y de código subyacente. Luego, pone a disposición todas las clases, interfaces y clases abstractas y sus métodos y propiedades en la página actual.

    Ejemplo:

    using System.IO;
  2. Como una declaración

    Esta es otra forma de usar la usingpalabra clave en C #. Desempeña un papel vital en la mejora del rendimiento en la recolección de basura.

    La usinginstrucción garantiza que se llame a Dispose () incluso si se produce una excepción al crear objetos y llamar a métodos, propiedades, etc. Dispose () es un método que está presente en la interfaz IDisposable que ayuda a implementar la recolección de basura personalizada. En otras palabras, si estoy haciendo alguna operación de la base de datos (Insertar, Actualizar, Eliminar) pero de alguna manera ocurre una excepción, aquí la declaración de uso cierra la conexión automáticamente. No es necesario llamar al método de conexión Close () explícitamente.

    Otro factor importante es que ayuda en la agrupación de conexiones. La agrupación de conexiones en .NET ayuda a eliminar el cierre de una conexión de base de datos varias veces. Envía el objeto de conexión a un grupo para uso futuro (próxima llamada a la base de datos). La próxima vez que se llame a una conexión de base de datos desde su aplicación, el grupo de conexiones busca los objetos disponibles en el grupo. Por lo tanto, ayuda a mejorar el rendimiento de la aplicación. Entonces, cuando usamos la declaración de uso, el controlador envía el objeto al grupo de conexiones automáticamente, no hay necesidad de llamar explícitamente a los métodos Close () y Dispose ().

    Puede hacer lo mismo que lo que está haciendo la instrucción using utilizando el bloque try-catch y llamando a Dispose () dentro del bloque finalmente explícitamente. Pero la declaración de uso hace las llamadas automáticamente para que el código sea más limpio y elegante. Dentro del bloque de uso, el objeto es de solo lectura y no se puede modificar ni reasignar.

    Ejemplo:

    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));
          }
    }

En el código anterior no estoy cerrando ninguna conexión; Se cerrará automáticamente. La usinginstrucción llamará a conn.Close () automáticamente debido a la usinginstrucción ( using (SqlConnection conn = new SqlConnection(connString)) y lo mismo para un objeto SqlDataReader. Y también, si ocurre alguna excepción, cerrará la conexión automáticamente.

Para obtener más información, consulte Uso e importancia del uso en C # .

Chamila Maddumage
fuente
-1

usar como una declaración llama automáticamente a la disposición en el objeto especificado. El objeto debe implementar la interfaz IDisposable. Es posible usar varios objetos en una declaración siempre que sean del mismo tipo.

El CLR convierte su código en MSIL. Y la declaración de uso se traduce en un intento y finalmente se bloquea. Así es como se representa la instrucción using en IL. Una declaración de uso se traduce en tres partes: adquisición, uso y eliminación. El recurso se adquiere primero, luego el uso se incluye en una declaración de prueba con una cláusula finalmente. El objeto se elimina en la cláusula final.

Vazgen Torosyan
fuente
-3

El uso de Cláusula se utiliza para definir el alcance de la variable particular. Por ejemplo:

     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
fuente
Esto podría confundir a alguien, el uso es para deshacerse de objetos. Quizás esté confundiendo esto con el bloque de código, si desea limitar el alcance de una variable, puede usar el bloque de código anidado para eso: public static void Main (cadena de parámetros [] args) {{// bloque de código anidado}}
luiseduardohd