Пользователь kokos ответил на замечательный вопрос о скрытых возможностях C # , упомянув using
ключевое слово. Можете ли вы уточнить это? Каковы виды использования using
?
Пользователь kokos ответил на замечательный вопрос о скрытых возможностях C # , упомянув using
ключевое слово. Можете ли вы уточнить это? Каковы виды использования using
?
Ответы:
Причина этого using
утверждения заключается в том, чтобы гарантировать, что объект удаляется, как только он выходит из области видимости, и для этого не требуется явный код.
Как и в разделе «Понимание выражения« использование »в C # (codeproject) и« Использование объектов, реализующих IDisposable (microsoft) » , компилятор C # преобразует
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();
}
}
C # 8 вводит новый синтаксис, названный « использование объявлений »:
Объявление использования - это объявление переменной, которому предшествует ключевое слово using. Он сообщает компилятору, что объявленная переменная должна быть расположена в конце области видимости.
Таким образом, эквивалентный код выше будет:
using var myRes = new MyResource();
myRes.DoSomething();
И когда элемент управления покидает содержащую область (обычно это метод, но это также может быть блок кода), myRes
он удаляется.
using
удостоверится, что он Dispose
вызывается, как только вы закончите с объектом.
MyRessource
структуры. Там явно нет теста на ничтожность, но и нет бокса IDisposable
. Ограниченный виртуальный вызов испускается.
using
, переменная, встроенная в нее, доступна только для чтения. Нет способа достичь этого для локальных переменных без using
оператора.
Поскольку многие люди до сих пор делают:
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
.
return
из середины using
блока.
используя, в смысле
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- Definitive-реф книга / дп / 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;
}
}
}
Это то, что нужно принять с умом, поскольку злоупотребление этой практикой может повредить ясности кода. В DotNetPearls есть хорошее объяснение псевдонимов C #, а также упоминания о плюсах и минусах ( http://www.dotnetperls.com/using-alias ).
using
в качестве псевдонима. Это смущает меня при чтении кода - я уже знаю, что System.Collections
существует и имеет IEnumerable<T>
класс. Использование псевдонима, чтобы назвать это чем-то другим, скрывает это для меня. Я вижу using FooCollection = IEnumerable<Foo>
способ заставить более поздних разработчиков читать код и думать: «Что за чертовщина FooCollection
и почему для нее где-то не существует класса?» Я никогда не использую это и буду препятствовать его использованию. Но это может быть только я.
В прошлом я много использовал его для работы с потоками ввода и вывода. Вы можете удобно их вкладывать, и это устраняет многие потенциальные проблемы, с которыми вы обычно сталкиваетесь (автоматически вызывая 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
В заключение, когда вы используете локальную переменную типа, который реализует IDisposable
, всегда без исключения используйте using
1 .
Если вы используете нелокальные IDisposable
переменные, то всегда реализуйте IDisposable
шаблон .
Два простых правила, без исключения 1 . Предотвращение утечек ресурсов - это настоящая боль в * ss.
1) : единственное исключение - когда вы обрабатываете исключения. Тогда может быть меньше кода для Dispose
явного вызова в finally
блоке.
Вы можете использовать пространство имен псевдонимов в следующем примере:
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.
При использовании ADO.NET вы можете использовать клавиши для таких вещей, как объект подключения или объект чтения. Таким образом, когда блок кода завершится, он автоматически избавится от вашего соединения.
«Использование» также может быть использовано для разрешения конфликтов пространства имен. Смотрите http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/ для краткого учебника, который я написал на эту тему.
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
}
}
Использование используется, когда у вас есть ресурс, который вы хотите утилизировать после его использования.
Например, если вы выделяете ресурс File и вам нужно использовать его только в одном разделе кода для небольшого чтения или записи, использование полезно для удаления ресурса File, как только вы закончите.
Используемый ресурс должен реализовывать IDisposable для правильной работы.
Пример:
using (File file = new File (parameters))
{
*code to do stuff with the file*
}
Ключевое слово using определяет область действия объекта, а затем удаляет объект после завершения области действия. Например.
using (Font font2 = new Font("Arial", 10.0f))
{
// use font2
}
Смотрите здесь статью MSDN о C # используя ключевое слово.
Не то чтобы это очень важно, но использование может также использоваться для изменения ресурсов на лету. Да, одноразовые, как уже упоминалось ранее, но, возможно, вам не нужны ресурсы, которые они не соответствуют другим ресурсам во время остальной части вашего исполнения. Таким образом, вы хотите избавиться от него, чтобы он не мешал в другом месте.
Благодаря комментариям, приведенным ниже, я немного исправлю этот пост (я не должен был использовать слова «сборка мусора» в то время, извинения):
когда вы используете, он вызовет метод Dispose () для объекта в конце области использования. Таким образом, вы можете иметь довольно много отличного кода для очистки в вашем методе Dispose ().
Пуля, которая, как мы надеемся, может получить это незаметное: Если вы реализуете IDisposable, убедитесь, что вы вызываете GC.SuppressFinalize () в вашей реализации Dispose (), так как в противном случае автоматическая сборка мусора попытается прийти и завершить ее в некоторых случаях. точка, которая, по крайней мере, будет пустой тратой ресурсов, если вы уже утилизировали () d этого.
Еще один пример разумного использования, при котором объект сразу же утилизируется:
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 обеспечивает удобный механизм для правильного использования IDisposable объектов. Как правило, когда вы используете объект IDisposable, вы должны объявить и создать его экземпляр в операторе using. Оператор using вызывает метод Dispose для объекта правильным образом и (при использовании его, как показано ранее) также вызывает выход объекта из области действия сразу после вызова Dispose. Внутри блока using объект доступен только для чтения и не может быть изменен или переназначен.
Это происходит от: здесь
Это также может быть использовано для создания областей, например:
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 указывает .NET освободить объект, указанный в блоке using, когда он больше не нужен. Поэтому вы должны использовать блок «using» для классов, которые требуют очистки после них, таких как System.IO Types.
Существует два использования using
ключевого слова в C # следующим образом.
Как директива
Обычно мы используем using
ключевое слово для добавления пространств имен в коде и файлах классов. Затем он делает доступными все классы, интерфейсы и абстрактные классы, а также их методы и свойства на текущей странице.
Пример:
using System.IO;
Как утверждение
Это еще один способ использовать 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. А также, если произойдет какое-либо исключение, оно автоматически закроет соединение.
Для получения дополнительной информации см. Использование и важность использования в C # .
Rhino Mocks Запись-воспроизведение Синтаксис делает интересное применение 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.
}