Каковы виды использования "using" в C#

Пользователь kokos ответил на замечательный вопрос о скрытых возможностях C#, упомянув using ключевое слово. Можете ли вы уточнить это? Каковы виды использования using?

29 ответов

Решение

Причина для using оператор должен гарантировать, что объект удаляется, как только он выходит из области видимости, и для этого не требуется явный код.

Как и в " Понимании оператора using" в C#,.NET CLR преобразует

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

в

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

Поскольку многие люди до сих пор делают:

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

Я думаю, что многие люди до сих пор не знают, что вы можете сделать:

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

Вещи как это:

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

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

это SqlConnection будет закрыт без необходимости явного вызова .Close() функция, и это произойдет, даже если выдается исключение, без необходимости try/catch/finally,

Использование может быть использовано для вызова IDisposable. Он также может быть использован для псевдонимов типов.

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

Используя, в смысле

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

Это на самом деле сокращение для блока try/finally. Это эквивалентно коду:

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

Вы, конечно, заметите, что первый фрагмент гораздо более лаконичен, чем второй, а также есть множество вещей, которые вы можете захотеть сделать для очистки, даже если выдается исключение. Из-за этого мы создали класс, который мы называем Scope, который позволяет вам выполнять произвольный код в методе Dispose. Так, например, если у вас было свойство IsWorking, которое вы всегда хотели установить в false после попытки выполнить операцию, вы бы сделали это так:

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

Подробнее о нашем решении и о том, как мы его получили, вы можете прочитать здесь.

Документация Microsoft гласит, что использование имеет двойную функцию ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx), как в качестве директивы, так и в выражениях. В качестве утверждения, как указывалось здесь в других ответах, ключевое слово в основном является синтаксическим сахаром для определения области действия для удаления объекта IDisposable. Как директива, она обычно используется для импорта пространств имен и типов. Также в качестве директивы вы можете создавать псевдонимы для пространств имен и типов, как указано в книге "C# 5.0 в двух словах: полное руководство" ( http://www.amazon.com/5-0-Nutshell-The- Definition-Reference-ebook / dp / B008E6I1K8) Джозефа и Бена Албахари. Один пример:

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

Это то, что нужно принимать с умом, поскольку злоупотребление этой практикой может повредить ясности кода. Хорошее объяснение псевдонимов C#, а также упоминание о плюсах и минусах, можно найти в DotNetPearls ( http://www.dotnetperls.com/using-alias).

В прошлом я много использовал его для работы с потоками ввода и вывода. Вы можете удобно их вкладывать, и это устраняет многие потенциальные проблемы, с которыми вы обычно сталкиваетесь (автоматически вызывая dispose). Например:

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

Просто добавив немного чего-то, что меня удивило, не подошло. Самая интересная особенность использования (на мой взгляд) заключается в том, что независимо от того, как вы выйдете из блока использования, он всегда будет располагать объектом. Это включает в себя возвраты и исключения.

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

Не имеет значения, было ли выброшено исключение или возвращен список. Объект DbContext всегда будет расположен.

Еще одно замечательное применение - это создание модального диалога.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

Вы можете использовать пространство имен псевдонимов в следующем примере:

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

Это называется директивой using alias, поскольку, как вы можете видеть, ее можно использовать для сокрытия длинных ссылок, если вы хотите, чтобы в вашем коде было очевидно, на что вы ссылаетесь, например:

LegacyEntities.Account

вместо

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

или просто

Account   // It is not obvious this is a legacy entity

Интересно, что вы также можете использовать шаблон использования /IDisposable для других интересных вещей (например, другой момент, которым его использует Rhino Mocks). По сути, вы можете воспользоваться тем фактом, что компилятор всегда будет вызывать.Dispose для "используемого" объекта. Если у вас есть что-то, что должно произойти после определенной операции... что-то с определенным началом и концом... тогда вы можете просто создать класс IDisposable, который запускает операцию в конструкторе, а затем завершается в методе Dispose.

Это позволяет вам использовать действительно хороший синтаксис для обозначения явного начала и конца указанной операции. Так же работает и материал System.Transaction.

В заключение, когда вы используете локальную переменную типа, который реализует IDisposableвсегда без исключения использую using1

Если вы используете нелокальный IDisposable переменные, то всегда реализуйте IDisposable образец

Два простых правила, не исключение1. Предотвращение утечки ресурсов в противном случае является настоящей болью в * ss.


1): единственное исключение - когда вы обрабатываете исключения. Тогда может быть меньше кода для вызова Dispose явно в finally блок.

Существует два варианта использования ключевого слова в C# следующим образом.

  1. как директива

Обычно мы используем ключевое слово using для добавления пространств имен в коде и файлах классов. Затем он делает доступными все классы, интерфейсы и абстрактные классы, а также их методы и свойства на текущей странице.

Пример:

using System.IO;  
  1. как заявление

Это еще один способ использовать ключевое слово using в C#. Это играет жизненно важную роль в повышении производительности сборки мусора. Оператор using гарантирует, что Dispose() вызывается, даже если возникает исключение при создании объектов и вызове методов, свойств и т. Д. Dispose() - это метод, присутствующий в интерфейсе IDisposable, который помогает реализовать пользовательскую сборку мусора. Другими словами, если я выполняю какую-либо операцию с базой данных (Вставка, Обновление, Удаление), но каким-то образом происходит исключение, то здесь оператор using автоматически закрывает соединение. Нет необходимости вызывать метод Close() явно.

Другим важным фактором является то, что он помогает в пуле подключений. Пул соединений в.NET помогает многократно исключить закрытие соединения с базой данных. Он отправляет объект подключения в пул для будущего использования (следующий вызов базы данных). При следующем вызове соединения с базой данных из вашего приложения пул соединений извлекает объекты, доступные в пуле. Так что это помогает улучшить производительность приложения. Поэтому, когда мы используем оператор using, контроллер автоматически отправляет объект в пул соединений, поэтому нет необходимости явно вызывать методы Close() и Dispose().

Вы можете сделать то же самое, что и оператор using, используя блок try-catch и явно вызывая Dispose() внутри блока finally. Но оператор using делает вызовы автоматически, чтобы сделать код чище и элегантнее. Внутри блока using объект доступен только для чтения и не может быть изменен или переназначен.

Пример:

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

В предыдущем коде я не закрываю соединение, оно автоматически закрывается. Оператор using вызовет conn.Close() автоматически из-за оператора using (using (SqlConnection conn = new SqlConnection(connString)) и того же для объекта SqlDataReader. А также, если произойдет любое исключение, он автоматически закроет соединение.

Для получения дополнительной информации -> https://www.c-sharpcorner.com/UploadFile/manas1/usage-and-importance-of-using-in-C-Sharp472/

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

При использовании ADO.NET вы можете использовать клавиши для таких вещей, как объект подключения или объект чтения. Таким образом, когда блок кода завершится, он автоматически избавится от вашего соединения.

"using" также может использоваться для разрешения конфликтов пространства имен. Смотрите http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/ для краткого учебника, который я написал по этому вопросу.

Использование используется, когда у вас есть ресурс, который вы хотите утилизировать после его использования.

Например, если вы выделяете ресурс File и вам нужно использовать его только в одном разделе кода для небольшого чтения или записи, использование полезно для удаления ресурса File, как только вы закончите.

Используемый ресурс должен реализовывать IDisposable для правильной работы.

Пример:

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

Синтаксис Rhino Mocks Record-play делает интересное использование using,

Еще один пример разумного использования, при котором объект сразу же утилизируется:

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

Все, что находится вне фигурных скобок, расположено так, что если вы не пользуетесь ими, это здорово. Это так, потому что если у вас есть объект SqlDataAdapter и вы используете его только один раз в жизненном цикле приложения, и вы заполняете только один набор данных, и он вам больше не нужен, вы можете использовать код:

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

Для меня имя "использование" немного сбивает с толку, потому что это может быть директивой для импорта пространства имен или оператора (как обсуждалось здесь) для обработки ошибок.

Было бы неплохо другое имя для обработки ошибок, а может быть, и более очевидное.

Благодаря комментариям ниже, я немного почисту этот пост (я не должен был использовать слова "сборка мусора" в то время, извинения):
Когда вы используете using, он вызовет метод Dispose() для объекта в конце области применения. Таким образом, вы можете иметь довольно много отличного кода для очистки в вашем методе Dispose().
Пуля, которая, как мы надеемся, может получить это незаметное: Если вы реализуете IDisposable, убедитесь, что вы вызываете GC.SuppressFinalize() в вашей реализации Dispose(), так как в противном случае автоматическая сборка мусора попытается прийти и завершить ее в некоторых случаях. точка, которая, по крайней мере, будет пустой тратой ресурсов, если вы уже утилизировали ()d этого.

Ключевое слово using определяет область действия объекта, а затем удаляет объект после завершения области действия. Например.

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

Смотрите здесь статью MSDN о C# используя ключевое слово.

Не то чтобы это очень важно, но использование может также использоваться для изменения ресурсов на лету. Да, одноразовые, как уже упоминалось ранее, но, возможно, вам не нужны ресурсы, которые они не соответствуют другим ресурсам во время остальной части исполнения. Таким образом, вы хотите избавиться от него, чтобы он не мешал в другом месте.

Оператор using указывает.NET освободить объект, указанный в блоке using, когда он больше не нужен. Поэтому вы должны использовать блок "using" для классов, которые требуют очистки после них, таких как System.IO Types.

Это также может быть использовано для создания областей, например:

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

}

Оператор using обеспечивает удобный механизм для правильного использования IDisposable объектов. Как правило, когда вы используете объект IDisposable, вы должны объявить и создать его экземпляр в операторе using. Оператор using вызывает метод Dispose для объекта правильным образом и (когда вы используете его, как показано ранее), он также заставляет сам объект выходить из области действия при вызове Dispose. Внутри блока using объект доступен только для чтения и не может быть изменен или переназначен.

Это происходит от: здесь

использование в качестве оператора автоматически вызывает удаление для указанного объекта. Объект должен реализовывать интерфейс IDisposable. Можно использовать несколько объектов в одном выражении, если они одного типа.

CLR преобразует ваш код в MSIL. И оператор using переводится в блок try and finally. Вот как оператор использования представлен в IL. Заявление об использовании переводится на три части: приобретение, использование и утилизация. Ресурс сначала запрашивается, затем использование включается в оператор try с предложением finally. Затем объект удаляется в предложении finally.

Использование Clause используется для определения области действия определенной переменной. Например:

     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.
            }
Другие вопросы по тегам