Користувач kokos відповів на чудові приховані особливості C # питання, згадуючи using
ключове слово. Чи можете ви детальніше розглянути це? В чому користь using
?
Користувач kokos відповів на чудові приховані особливості C # питання, згадуючи using
ключове слово. Чи можете ви детальніше розглянути це? В чому користь 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 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()
функції, і це станеться, навіть якщо буде викинуто виняток , без необхідності a try
/ catch
/ finally
.
return
із середини using
блоку.
використання, в сенсі
using (var foo = new Bar())
{
Baz();
}
Насправді це стенограма для блоку спробу / нарешті. Він еквівалентний коду:
var foo = new Bar();
try
{
Baz();
}
finally
{
foo.Dispose();
}
Звичайно, ви зауважите, що перший фрагмент набагато більш стислий, ніж другий, а також, що є багато видів, які ви можете зробити як очищення, навіть якщо буде викинуто виняток. Через це ми створили клас, який ми називаємо Scope, який дозволяє виконувати довільний код у методі Dispose. Так, наприклад, якщо у вас був властивість під назвою IsWorking, яке ви завжди хотіли встановити на помилковий після спроби виконати операцію, ви зробите це так:
using (new Scope(() => IsWorking = false))
{
IsWorking = true;
MundaneYetDangerousWork();
}
Ви можете прочитати більше про наше рішення та про те, як ми його отримали тут .
У документації Microsoft зазначається, що використання має подвійну функцію ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), як в якості директиви, так і в заявах . Як твердження , як вказувалося тут в інших відповідях, ключове слово - це в основному синтаксичний цукор для визначення сфери розпорядження об'єктом, що не використовує ідентифікацію . Як директива , вона звичайно використовується для імпорту просторів імен та типів. Також в якості директиви ви можете створювати псевдоніми для просторів імен та типів, як зазначено в книзі "C # 5.0 In Nutshell: The Final Guide" ( http://www.amazon.com/5-0-Nutshell-The- Остаточний-довідник-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 ).
using
псевдоніму. Це мене бентежить при читанні коду - я вже знаю, що System.Collections
існує і є IEnumerable<T>
клас. Використання псевдоніма для того, щоб назвати його чимось іншим, заплутує його для мене. Я розглядаю using FooCollection = IEnumerable<Foo>
як спосіб змусити пізніше розробників прочитати код і подумати: "Що за чорт FooCollection
і чому там десь не існує клас?" Я ніколи не користуюся ним і не перешкоджаю б його використанню. Але це я можу просто я.
У минулому я його багато використовував для роботи з вхідними та вихідними потоками. Ви можете їх добре гніздувати, і це забирає багато можливих проблем, з якими ви зазвичай стикаєтесь (автоматично викликаючи розпорядження). Наприклад:
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;
Це називається директивою з використанням псевдоніму , як ви бачите, вона може використовуватися для приховування довгомоторних посилань, якщо ви хочете, щоб у вашому коді стало очевидним те, що ви маєте на увазі, наприклад,
LegacyEntities.Account
замість
CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account
або просто
Account // It is not obvious this is a legacy entity
Цікаво, що ви також можете використовувати шаблон / IDisposable для інших цікавих речей (наприклад, іншого пункту, яким він користується Rhino Mocks). В основному, ви можете скористатися тим, що компілятор буде завжди викликати. Якщо у вас є щось, що повинно відбутися після певної операції ... щось, що має певний початок і кінець ..., ви можете просто зробити клас Idisposable, який запустить операцію в конструкторі, а потім закінчить методом Dispose.
Це дозволяє використовувати синтаксис справді добре, щоб позначити явний початок і кінець зазначеної операції. Так працює матеріал System.Transaction.
Під час використання ADO.NET ви можете використовувати ключові роботи для таких речей, як об’єкт підключення чи об'єкт зчитування. Таким чином, коли блок коду завершиться, він автоматично розпоряджатиметься вашим з'єднанням.
"using" може також використовуватися для вирішення конфліктів у просторі імен. Див. 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
}
}
використання використовується, коли у вас є ресурс, який ви хочете розмістити після його використання.
Наприклад, якщо ви виділите файл-ресурс і вам потрібно використовувати його лише в одному розділі коду для невеликого читання або запису, використання корисно для видалення файлового ресурсу, як тільки ви це зробите.
Ресурс, який використовується, повинен реалізувати IDisposable для належної роботи.
Приклад:
using (File file = new File (parameters))
{
*code to do stuff with the file*
}
Ключове слово, що використовує, визначає область для об'єкта, а потім розпоряджається об'єктом після завершення області. Наприклад.
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
Оператор, що використовує, забезпечує механізм зручності для правильного використання об'єктів, що використовуються для ідентифікації. Як правило, коли ви використовуєте об'єкт, що не використовується, ви повинні оголосити його та використати в операторі, що використовує. Оператор, що використовує, викликає метод об'єкта правильним чином і (коли ви використовуєте його, як показано раніше), також призводить до того, що сам об'єкт виходить із сфери дії, як тільки викликається Dispose. У блоці, що використовує, об'єкт є лише для читання, і його не можна змінювати чи перепризначати.
Це походить від: ось
Він також може бути використаний для створення областей для Прикладу:
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);
}
}
}
}
Використовуючи оператор повідомляє .NET звільняти об'єкт, вказаний у використанні блоку, як тільки він більше не потрібен. Тому слід використовувати блок "використання" для класів, які потребують очищення після них, як-от Типи System.IO.
Існує два використання using
ключового слова в C # наступним чином.
Як директива
Зазвичай ми використовуємо using
ключове слово для додавання просторів імен у файли коду та класи. Потім він робить доступними всі класи, інтерфейси та абстрактні класи та їх методи та властивості на поточній сторінці.
Приклад:
using System.IO;
Як заява
Це ще один спосіб використання using
ключового слова в C #. Він відіграє важливу роль у покращенні продуктивності збору сміття.
The using
заяві гарантує , що Dispose () викликається , навіть якщо виключення виникає при створенні об'єктів і виклику методів, властивостей і так далі. Dispose () - метод, який присутній в інтерфейсі IDisposable, який допомагає реалізувати власну збір сміття. Іншими словами, якщо я роблю деяку операцію з базою даних (Вставити, Оновити, Видалити), але якимось чином виняток виникає, то тут використовуючий оператор закриває з'єднання автоматично. Не потрібно чітко викликати з'єднання методом Close ().
Ще одним важливим фактором є те, що він допомагає в Об'єднанні. Пул з'єднання в .NET допомагає усунути закриття з'єднання з базою даних кілька разів. Він посилає об’єкт з'єднання в пул для подальшого використання (наступний виклик бази даних). Наступного разу, коли з вашої програми буде викликано з'єднання з базою даних, пул з'єднань вибирає об'єкти, наявні в пулі. Так це допомагає покращити продуктивність програми. Отже, коли ми використовуємо оператор, що використовує контролер, автоматично надсилає об'єкт до пулу з'єднання, немає необхідності чітко викликати методи Close () та Dispose ().
Ви можете зробити те ж саме, що робить оператор using, використовуючи блок try-catch і викличте Dispose () всередині остаточного блоку явно. Але оператор використання робить дзвінки автоматично, щоб зробити код більш чистим та елегантним. У блоці, що використовує, об'єкт є лише для читання, і його не можна змінювати чи перепризначати.
Приклад:
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 переводиться на спробу і остаточно блокує. Ось так представлений використовуваний оператор в IL. Використовуючий оператор перекладається на три частини: придбання, використання та розпорядження. Спочатку отримується ресурс, потім використання вкладається у спробу оператора з остаточно застереженням. Потім об'єкт розміщується в остаточному пункті.
Використовуючи пункт, використовується для визначення області для конкретної змінної. Наприклад:
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.
}