2010-08-02 11 views
17

सी # में बयान उपयोग करने के उदाहरण में से अधिकांश इस तरह कोष्ठकों में वस्तु की घोषणा:एक वस्तु एक बयान का उपयोग करके उपरोक्त बजाय कोष्ठक में घोषित किया जा सकता है

using (SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", connection)) 
{ 
    // Code goes here 
} 

अगर मैं का उपयोग कर का उपयोग क्या होता है

SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", connection); 
using (cmd) 
{ 
    // Code goes here 
} 

यह एक बुरा विचार दूसरे उदाहरण में और क्यों तरह से बयान मैं का उपयोग कर उपयोग करने के लिए है: वस्तु के साथ निम्नलिखित तरीके से कथन का उपयोग बयान के बाहर घोषित?

उत्तर

15

उपयोग कथन की नियंत्रण अभिव्यक्ति के अंदर चर को घोषित करने से वेरिएबल के दायरे को उपयोग कथन के अंदर सीमित कर दिया जाता है। आपके दूसरे उदाहरण में परिवर्तनीय cmd उपयोग कथन के बाद उपयोग किया जा सकता है (जब इसे निपटाया जाएगा)।

आम तौर पर केवल एक उद्देश्य के लिए एक चर का उपयोग करने की अनुशंसा की जाती है, इसके दायरे को सीमित करने के बाद बाद में उसी नाम के साथ एक अन्य कमांड को अनुमति मिलती है (शायद अभिव्यक्ति का उपयोग करके दूसरे में)। शायद अधिक महत्वपूर्ण बात यह है कि यह आपके कोड के पाठक को बताता है (और रखरखाव प्रारंभिक लेखन से अधिक प्रयास करता है) cmd का उपयोग कथन से परे नहीं किया जाता है: आपका कोड थोड़ा और समझ में आता है।

6

हां, यह मान्य है - ऑब्जेक्ट को अभी भी उसी तरीके से निपटाया जाएगा, यानी अंत में और यदि निष्पादन प्रवाह ब्लॉक (वापसी/अपवाद) छोड़ने का प्रयास करता है।

हालांकि यदि आप using के बाद इसे फिर से उपयोग करने का प्रयास करते हैं, तो इसका निपटारा किया जाएगा, इसलिए आप यह नहीं जान सकते कि यह उदाहरण निपटान जारी रखने के लिए सुरक्षित है या नहीं, ऑब्जेक्ट स्थिति को रीसेट करने की आवश्यकता नहीं है। अगर निर्माण के दौरान कोई अपवाद होता है, तो यह using ब्लॉक को हिट नहीं करेगा।

मैं अपने दायरे को परिभाषित करने के लिए कथन के अंदर चर को घोषित और आरंभ कर दूंगा। संभावनाएं बहुत अच्छी हैं यदि आपको using का उपयोग कर रहे हैं तो आपको दायरे के बाहर इसकी आवश्यकता नहीं होगी।

MemoryStream ms = new MemoryStream(); // Initialisation not compiled into the using. 

using (ms) { } 

int i = ms.ReadByte(); // Will fail on closed stream. 

नीचे ज्यादातर मामलों में मान्य है, लेकिन कुछ हद तक अनावश्यक है:

MemoryStream ms = null; 

using (ms = new MemoryStream()) 
{ } 

// Do not continue to use ms unless re-initializing. 
+0

यह अभी भी 'using' के बाद उपलब्ध होगा:

तो यहाँ मेरी स्रोत कोड एक (लंबी) परीक्षा में शामिल है। – Anax

+2

यह उपलब्ध होगा लेकिन प्रयोग योग्य नहीं होगा - यह आंतरिक स्थिति का निपटारा किया जाएगा। आपको पता नहीं है कि आंतरिक स्थिति क्या है या कैसे निपटान कक्षा के उदाहरण को प्रभावित करता है, इसलिए यह एक सुरक्षित पाठ्यक्रम नहीं है। मैंने यह नहीं कहा कि यह उपलब्ध नहीं होगा, -1 लागू नहीं है। –

+0

मेरा मानना ​​है कि कन्स्ट्रक्टर का उपयोग ब्लॉक के भीतर निष्पादित किया गया है, भले ही कन्स्ट्रक्टर फेंकता है तो निपटान नहीं किया जाएगा। – Henrik

1

using के पीछे विचार यह define a scope, outside of which an object or objects will be disposed है।

यदि आप ऑब्जेक्ट को using के अंदर उपयोग करने वाले हैं, तो using कथन का उपयोग करने का कोई मतलब नहीं है।

+1

तकनीकी रूप से अभी भी एक बिंदु है, क्योंकि यह अभी भी सही तरीके से व्यवहार करेगा और वस्तु का निपटान करेगा। * प्रारंभिक * यह उपयोग ब्लॉक के बाहर खतरनाक हो सकता है, क्योंकि यह ब्लॉक के व्यवहार का उपयोग करके कवर नहीं किया जाएगा। –

1

इसका उत्तर दिया गया है और उत्तर है: हाँ, यह संभव है।
हालांकि, प्रोग्रामर दृष्टिकोण से, ऐसा मत करो! यह किसी भी प्रोग्रामर को भ्रमित करेगा जो इस कोड पर काम करेगा और इस तरह के निर्माण की उम्मीद नहीं करता है। असल में, यदि आप किसी और को काम करने के लिए कोड देते हैं, तो वह अन्य व्यक्ति बहुत ही भ्रमित हो सकता है अगर वे उपयोग के बाद "cmd" चर का उपयोग करते हैं। ऑब्जेक्ट के निर्माण और "उपयोग" भाग के बीच कोड की और भी रेखाएं होने पर यह और भी बदतर हो जाती है।

1

मैंने कुछ यूनिट परीक्षणों के साथ एक छोटा कोड लिखा था। मुझे यह पसंद है जब मैं हाथ में सवाल के बारे में बयान मान्य कर सकता हूं।मेरे निष्कर्ष:

  • चाहे कोई ऑब्जेक्ट using कथन से पहले या उसके बाद बनाया गया हो, कोई फर्क नहीं पड़ता। इसे IDisposable और Dispose() को लागू करना होगा कथन कथन ब्लॉक (बंद ब्रेस) छोड़ने पर कॉल किया जाएगा।
  • यदि कन्स्ट्रक्टर Dispose() का उपयोग नहीं किया जाता है तो कन्स्ट्रक्टर अपवाद फेंकता है। यह उचित है क्योंकि कन्स्ट्रक्टर में अपवाद फेंकने पर वस्तु का सफलतापूर्वक निर्माण नहीं किया गया है। इसलिए उस बिंदु पर कोई उदाहरण मौजूद नहीं है और ऑब्जेक्ट पर कॉलिंग इंस्टेंस सदस्यों (गैर स्थैतिक सदस्यों) को समझ में नहीं आता है। इसमें Dispose() शामिल है।

मेरे निष्कर्षों को पुन: उत्पन्न करने के लिए, कृपया नीचे स्रोत कोड देखें।

तो नीचे की रेखा जो आप कर सकते हैं - जैसा कि दूसरों द्वारा इंगित किया गया है - किसी ऑब्जेक्ट को उपयोग कथन से पहले तत्काल करें और फिर इसे उपयोग कथन के अंदर उपयोग करें। मैं भी सहमत हूं, हालांकि, उपयोग कथन के बाहर निर्माण को स्थानांतरित करने से कोड कम हो जाता है जो कम पठनीय है।

एक और वस्तु जिसे आप जानना चाहते हैं, यह तथ्य यह है कि कुछ कक्षाएं Dispose() कार्यान्वयन में अपवाद फेंक सकती हैं। हालांकि दिशानिर्देश ऐसा नहीं करना है, यहां तक ​​कि माइक्रोसॉफ्ट के मामले भी हैं, उदाहरण के लिए जैसा कि here पर चर्चा की गई है।

public class Bar : IDisposable { 
    public Bar() { 
     DisposeCalled = false; 

    } 
    public void Blah() { 
     if (DisposeCalled) { 
      // object was disposed you shouldn't use it anymore 
      throw new ObjectDisposedException("Object was already disposed."); 
     } 
    } 

    public void Dispose() { 
     // give back/free up resources that were used by the Bar object 
     DisposeCalled = true; 
    } 

    public bool DisposeCalled { get; private set; } 
    } 

    public class ConstructorThrows : IDisposable { 
    public ConstructorThrows(int argument) { 
     throw new ArgumentException("argument"); 
    } 

    public void Dispose() { 
     Log.Info("Constructor.Dispose() called."); 
    } 
    } 

    [Test] 
    public void Foo() { 
    var bar = new Bar(); 
    using (bar) { 
     bar.Blah(); // ok to call 
    }// Upon hitting this closing brace Dispose() will be invoked on bar. 

    try { 
     bar.Blah(); // Throws ObjectDisposedException 
     Assert.Fail(); 
    } 
    catch(ObjectDisposedException) { 
     // This exception is expected here 
    } 

    using (bar = new Bar()) { // can reuse the variable, though 
     bar.Blah(); // Fine to call as this is a second instance. 
    } 

    // The following code demonstrates that Dispose() won't be called if 
    // the constructor throws an exception: 
    using (var throws = new ConstructorThrows(35)) { 

    } 
    } 
+0

यदि कन्स्ट्रक्टर फेंकता है तो संदर्भ को चर के लिए कभी असाइन नहीं किया जाता है - ऑब्जेक्ट का कोई संदर्भ नहीं है जिसके माध्यम से 'निपटान' को कॉल करना है। – Richard

संबंधित मुद्दे

 संबंधित मुद्दे