C# Language
कथन का उपयोग करना
खोज…
परिचय
एक सुविधाजनक वाक्यविन्यास प्रदान करता है जो आईडीसॉर्पोरेटिव ऑब्जेक्ट्स के सही उपयोग को सुनिश्चित करता है।
वाक्य - विन्यास
- उपयोग करना (डिस्पोजेबल) {}
- उपयोग करना (आईडीसोपायरी डिस्पोजेबल = नया MyDisposable ()) {}
टिप्पणियों
using
कथन में ऑब्जेक्ट को IDisposable
इंटरफ़ेस लागू करना होगा।
using(var obj = new MyObject())
{
}
class MyObject : IDisposable
{
public void Dispose()
{
// Cleanup
}
}
एमएसडीएन डॉक्स पर IDisposable
कार्यान्वयन के लिए और अधिक पूर्ण उदाहरण मिल सकते हैं।
स्टेटमेंट बेसिक्स का उपयोग करना
सिंटैक्टिक शुगर using
करना आपको यह गारंटी देता है कि एक स्पष्ट try-finally
बिना एक संसाधन को साफ किया जाता है। इसका मतलब है कि आपका कोड बहुत अधिक क्लीनर होगा, और आप गैर-प्रबंधित संसाधनों को लीक नहीं करेंगे।
मानक Dispose
क्लीनअप पैटर्न, उन वस्तुओं के लिए जो IDisposable
इंटरफ़ेस लागू करते हैं (जो FileStream
का आधार वर्ग Stream
.NET में करता है):
int Foo()
{
var fileName = "file.txt";
{
FileStream disposable = null;
try
{
disposable = File.Open(fileName, FileMode.Open);
return disposable.ReadByte();
}
finally
{
// finally blocks are always run
if (disposable != null) disposable.Dispose();
}
}
}
स्पष्ट try-finally
छिपाकर अपने सिंटैक्स using
:
int Foo()
{
var fileName = "file.txt";
using (var disposable = File.Open(fileName, FileMode.Open))
{
return disposable.ReadByte();
}
// disposable.Dispose is called even if we return earlier
}
वैसे ही जैसे finally
ब्लॉक हमेशा त्रुटियों या रिटर्न की परवाह किए बिना निष्पादित, using
हमेशा कहता Dispose()
, यहां तक कि एक त्रुटि की स्थिति में:
int Foo()
{
var fileName = "file.txt";
using (var disposable = File.Open(fileName, FileMode.Open))
{
throw new InvalidOperationException();
}
// disposable.Dispose is called even if we throw an exception earlier
}
नोट: चूँकि Dispose
को कोड फ्लो के बावजूद कहा जाता है, इसलिए यह सुनिश्चित करने के लिए एक अच्छा विचार है कि Dispose
कभी भी एक अपवाद नहीं फेंकता है जब आप IDisposable
लागू करते हैं। अन्यथा एक वास्तविक अपवाद नए अपवाद द्वारा ओवरराइड हो जाएगा जिसके परिणामस्वरूप डिबगिंग दुःस्वप्न होगा।
ब्लॉक का उपयोग करके लौटना
using ( var disposable = new DisposableItem() )
{
return disposable.SomeProperty;
}
कोशिश के शब्दार्थों के try..finally
using
करते using
ब्लॉक ब्लॉक का अनुवाद करता है, return
स्टेटमेंट अपेक्षा के अनुसार काम करता है - रिटर्न वैल्यू का मूल्यांकन finally
ब्लॉक होने से पहले किया जाता है और मान का निपटान किया जाता है। मूल्यांकन का क्रम इस प्रकार है:
-
try
शरीर का मूल्यांकन करें - मूल्यांकन और लौटे मूल्य कैश
- अंत में निष्पादित ब्लॉक
- कैश्ड रिटर्न वैल्यू लौटाएं
हालाँकि, आप परिवर्तनशील disposable
स्वयं वापस नहीं कर सकते हैं, क्योंकि इसमें अमान्य, प्रेषित संदर्भ - संबंधित उदाहरण देखें।
एक ब्लॉक के साथ कई स्टेटमेंट का उपयोग करना
नेस्टेड ब्रेसेस के कई स्तरों को जोड़े बिना बयानों using
कई नेस्टेड using
उपयोग करना संभव है। उदाहरण के लिए:
using (var input = File.OpenRead("input.txt"))
{
using (var output = File.OpenWrite("output.txt"))
{
input.CopyTo(output);
} // output is disposed here
} // input is disposed here
एक विकल्प लिखना है:
using (var input = File.OpenRead("input.txt"))
using (var output = File.OpenWrite("output.txt"))
{
input.CopyTo(output);
} // output and then input are disposed here
जो पहले उदाहरण के बराबर है।
नोट: नेस्टेड स्टेटमेंट using
Microsoft कोड विश्लेषण नियम CS2002 को ट्रिगर किया जा सकता है (स्पष्टीकरण के लिए इस उत्तर को देखें) और चेतावनी उत्पन्न करें। जैसा कि लिंक किए गए उत्तर में बताया गया है, आमतौर पर बयानों using
घोंसला बनाना सुरक्षित है।
जब using
कथन के प्रकार एक ही प्रकार के होते हैं, तो आप उन्हें अल्पविराम दे सकते हैं और केवल एक बार प्रकार निर्दिष्ट कर सकते हैं (हालाँकि यह असामान्य है):
using (FileStream file = File.Open("MyFile.txt"), file2 = File.Open("MyFile2.txt"))
{
}
इसका उपयोग तब भी किया जा सकता है जब प्रकारों में एक साझा पदानुक्रम हो:
using (Stream file = File.Open("MyFile.txt"), data = new MemoryStream())
{
}
उपरोक्त उदाहरण में var
कीवर्ड का उपयोग नहीं किया जा सकता है। एक संकलन त्रुटि होगी। यहां तक कि अल्पविराम से पृथक घोषणा तब भी काम नहीं करेगी जब घोषित चर में विभिन्न पदानुक्रम से प्रकार हों।
गोटचा: जिस संसाधन का आप निपटान कर रहे हैं, उसे वापस करना
निम्नलिखित एक बुरा विचार है क्योंकि इसे वापस करने से पहले db
वैरिएबल को डिस्पोज़ किया जाएगा।
public IDBContext GetDBContext()
{
using (var db = new DBContext())
{
return db;
}
}
इससे और भी सूक्ष्म गलतियाँ हो सकती हैं:
public IEnumerable<Person> GetPeople(int age)
{
using (var db = new DBContext())
{
return db.Persons.Where(p => p.Age == age);
}
}
यह ठीक लग रहा है, लेकिन पकड़ यह है कि LINQ अभिव्यक्ति मूल्यांकन आलसी है, और संभवतः बाद में ही निष्पादित किया जाएगा जब अंतर्निहित DBContext
पहले ही DBContext
चुका है।
तो संक्षेप में using
छोड़ने से पहले अभिव्यक्ति का मूल्यांकन नहीं किया जाता है। इस समस्या को, जो अभी भी का उपयोग करता है करने के लिए एक संभव समाधान using
, एक विधि है कि परिणाम की गणना करेगा फोन करके तुरंत मूल्यांकन करने के लिए अभिव्यक्ति पैदा करने के लिए है। उदाहरण के लिए ToList()
, ToArray()
, आदि। यदि आप Entity फ्रेमवर्क के नवीनतम संस्करण का उपयोग कर रहे हैं तो आप ToListAsync()
या ToArrayAsync()
जैसे async
समकक्षों का उपयोग कर सकते हैं।
नीचे आप कार्रवाई में उदाहरण पाते हैं:
public IEnumerable<Person> GetPeople(int age)
{
using (var db = new DBContext())
{
return db.Persons.Where(p => p.Age == age).ToList();
}
}
यह नोट करना महत्वपूर्ण है, हालांकि, कि ToList()
या ToArray()
को कॉल ToList()
, अभिव्यक्ति का उत्सुकता से मूल्यांकन किया जाएगा, जिसका अर्थ है कि निर्दिष्ट आयु वाले सभी व्यक्ति मेमोरी पर लोड किए जाएंगे, भले ही आप उन पर पुनरावृत्ति न करें।
बयानों का उपयोग करना अशक्त है
आपको null
लिए IDisposable
ऑब्जेक्ट की जांच करने की आवश्यकता नहीं है। using
से अपवाद नहीं होगा और Dispose()
नहीं कहा जाएगा:
DisposableObject TryOpenFile()
{
return null;
}
// disposable is null here, but this does not throw an exception
using (var disposable = TryOpenFile())
{
// this will throw a NullReferenceException because disposable is null
disposable.DoSomething();
if(disposable != null)
{
// here we are safe because disposable has been checked for null
disposable.DoSomething();
}
}
गोटचा: ब्लॉकों का उपयोग करने में अन्य त्रुटियों को मास्क करने की विधि में अपवाद
कोड के निम्नलिखित ब्लॉक पर विचार करें।
try
{
using (var disposable = new MyDisposable())
{
throw new Exception("Couldn't perform operation.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
class MyDisposable : IDisposable
{
public void Dispose()
{
throw new Exception("Couldn't dispose successfully.");
}
}
आप कंसोल में मुद्रित "ऑपरेशन नहीं कर सकते" देखने की उम्मीद कर सकते हैं लेकिन आप वास्तव में देखेंगे "सफलतापूर्वक निपटान नहीं कर सकता।" पहले अपवाद को फेंक दिए जाने के बाद भी डिस्पोज़ विधि को अभी भी कहा जाता है।
यह इस सूक्ष्मता से अवगत होने के लायक है क्योंकि यह वास्तविक त्रुटि को चिह्नित कर सकता है जो ऑब्जेक्ट को डिस्पोज़ होने से रोकता है और इसे डीबग करना कठिन बनाता है।
स्टेटमेंट और डेटाबेस कनेक्शंस का उपयोग करना
using
कीवर्ड यह सुनिश्चित करता है कि कथन के भीतर परिभाषित संसाधन केवल कथन के दायरे में ही मौजूद है। बयान के भीतर परिभाषित किसी भी संसाधन को IDisposable
इंटरफ़ेस को लागू करना होगा।
ये अविश्वसनीय रूप से महत्वपूर्ण हैं जब किसी भी कनेक्शन के साथ काम करते हैं जो IDisposable
इंटरफ़ेस को लागू करते हैं क्योंकि यह सुनिश्चित कर सकता है कि कनेक्शन न केवल ठीक से बंद हैं, बल्कि उनके संसाधनों को using
किए जाने के बाद मुक्त using
दिया जाता है।
आम IDisposable
डाटा कक्षाएं
निम्नलिखित में से कई डेटा से संबंधित वर्ग हैं जो IDisposable
इंटरफ़ेस को लागू करते हैं और एक using
कथन के लिए एकदम सही उम्मीदवार हैं:
-
SqlConnection
,SqlCommand
,SqlDataReader
, आदि। -
OleDbConnection
,OleDbCommand
,OleDbDataReader
, आदि। -
MySqlConnection
,MySqlCommand
,MySqlDbDataReader
, आदि। -
DbContext
ये सभी आमतौर पर C # के माध्यम से डेटा तक पहुंचने के लिए उपयोग किए जाते हैं और आमतौर पर डेटा-केंद्रित अनुप्रयोगों के निर्माण के दौरान सामना किया जाएगा। कई अन्य वर्गों का उल्लेख नहीं किया गया है जो एक ही FooConnection
, FooCommand
, FooDataReader
वर्गों को लागू करते हैं उसी तरह का व्यवहार करने की उम्मीद की जा सकती है।
ADO.NET कनेक्शन के लिए सामान्य एक्सेस पैटर्न
एक सामान्य पैटर्न जिसका उपयोग ADO.NET कनेक्शन के माध्यम से आपके डेटा तक पहुँचते समय किया जा सकता है, इस प्रकार दिख सकता है:
// This scopes the connection (your specific class may vary)
using(var connection = new SqlConnection("{your-connection-string}")
{
// Build your query
var query = "SELECT * FROM YourTable WHERE Property = @property");
// Scope your command to execute
using(var command = new SqlCommand(query, connection))
{
// Open your connection
connection.Open();
// Add your parameters here if necessary
// Execute your query as a reader (again scoped with a using statement)
using(var reader = command.ExecuteReader())
{
// Iterate through your results here
}
}
}
या यदि आप केवल एक सरल अद्यतन कर रहे थे और उसे रीडर की आवश्यकता नहीं थी, तो वही मूल अवधारणा लागू होगी:
using(var connection = new SqlConnection("{your-connection-string}"))
{
var query = "UPDATE YourTable SET Property = Value WHERE Foo = @foo";
using(var command = new SqlCommand(query,connection))
{
connection.Open();
// Add parameters here
// Perform your update
command.ExecuteNonQuery();
}
}
DataContexts के साथ स्टेटमेंट का उपयोग करना
कई ओआरएम जैसे कि एंटिटी फ्रेमवर्क एब्सट्रैक्शन कक्षाओं को उजागर करता है जो कि DbContext
तरह कक्षाओं के रूप में अंतर्निहित डेटाबेस के साथ बातचीत करने के लिए उपयोग किया जाता है। ये संदर्भ आम तौर पर IDisposable
इंटरफ़ेस को लागू करते हैं और जब संभव हो तब बयानों using
इसका लाभ उठाना चाहिए:
using(var context = new YourDbContext())
{
// Access your context and perform your query
var data = context.Widgets.ToList();
}
कस्टम स्कोप को परिभाषित करने के लिए डिस्पोज़ सिंटैक्स का उपयोग करना
कुछ उपयोग मामलों के लिए, आप कस्टम स्कोप को परिभाषित करने में मदद करने के लिए सिंटैक्स using
उपयोग कर सकते हैं। उदाहरण के लिए, आप किसी विशिष्ट संस्कृति में कोड निष्पादित करने के लिए निम्न वर्ग को परिभाषित कर सकते हैं।
public class CultureContext : IDisposable
{
private readonly CultureInfo originalCulture;
public CultureContext(string culture)
{
originalCulture = CultureInfo.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
}
public void Dispose()
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
फिर आप एक विशिष्ट संस्कृति में निष्पादित कोड के ब्लॉकों को परिभाषित करने के लिए इस वर्ग का उपयोग कर सकते हैं।
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
using (new CultureContext("nl-NL"))
{
// Code in this block uses the "nl-NL" culture
Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 25-12-2016 00:00:00
}
using (new CultureContext("es-ES"))
{
// Code in this block uses the "es-ES" culture
Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 25/12/2016 0:00:00
}
// Reverted back to the original culture
Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 12/25/2016 12:00:00 AM
नोट: जैसा कि हम CultureContext
उदाहरण का उपयोग नहीं करते हैं जिसे हम बनाते हैं, हम इसके लिए एक चर नहीं देते हैं।
इस तकनीक का उपयोग ASP.NET MVC में BeginForm
हेल्पर द्वारा किया जाता है।
अड़चन कोड संदर्भ में
यदि आपके पास कोड (एक दिनचर्या ) है जिसे आप एक विशिष्ट (बाधा) संदर्भ के तहत निष्पादित करना चाहते हैं, तो आप निर्भरता इंजेक्शन का उपयोग कर सकते हैं।
निम्न उदाहरण एक खुले एसएसएल कनेक्शन के तहत निष्पादित करने की बाधा को दर्शाता है। यह पहला भाग आपकी लाइब्रेरी या फ्रेमवर्क में होगा, जिसे आप ग्राहक कोड के सामने नहीं लाएँगे।
public static class SSLContext
{
// define the delegate to inject
public delegate void TunnelRoutine(BinaryReader sslReader, BinaryWriter sslWriter);
// this allows the routine to be executed under SSL
public static void ClientTunnel(TcpClient tcpClient, TunnelRoutine routine)
{
using (SslStream sslStream = new SslStream(tcpClient.GetStream(), true, _validate))
{
sslStream.AuthenticateAsClient(HOSTNAME, null, SslProtocols.Tls, false);
if (!sslStream.IsAuthenticated)
{
throw new SecurityException("SSL tunnel not authenticated");
}
if (!sslStream.IsEncrypted)
{
throw new SecurityException("SSL tunnel not encrypted");
}
using (BinaryReader sslReader = new BinaryReader(sslStream))
using (BinaryWriter sslWriter = new BinaryWriter(sslStream))
{
routine(sslReader, sslWriter);
}
}
}
}
अब जो क्लाइंट कोड SSL के तहत कुछ करना चाहता है, लेकिन सभी SSL विवरण को संभालना नहीं चाहता है। अब आप एसएसएल सुरंग के अंदर जो चाहें कर सकते हैं, उदाहरण के लिए एक सममित कुंजी का आदान-प्रदान करें:
public void ExchangeSymmetricKey(BinaryReader sslReader, BinaryWriter sslWriter)
{
byte[] bytes = new byte[8];
(new RNGCryptoServiceProvider()).GetNonZeroBytes(bytes);
sslWriter.Write(BitConverter.ToUInt64(bytes, 0));
}
आप इस दिनचर्या को इस प्रकार निष्पादित करते हैं:
SSLContext.ClientTunnel(tcpClient, this.ExchangeSymmetricKey);
ऐसा करने के लिए, आपको using()
क्लॉज़ की आवश्यकता है क्योंकि यह एकमात्र तरीका है (एक try..finally
ब्लॉक) आप ग्राहक कोड ( ExchangeSymmetricKey
) की गारंटी दे सकते हैं बिना डिस्पोजेबल संसाधनों के ठीक से निपटान किए बिना। using()
खंड के बिना, आप कभी नहीं जान पाएंगे कि क्या एक दिनचर्या उन संसाधनों के निपटान के लिए संदर्भ की बाधा को तोड़ सकती है।