जवाबों:
दूसरों ने पहले से ही अंतर को कवर किया है Disposeऔर Finalize(btw Finalizeविधि को अभी भी भाषा विनिर्देश में विध्वंसक कहा जाता है), इसलिए मैं उन परिदृश्यों के बारे में थोड़ा जोड़ूंगा जहां Finalizeविधि काम में आती है।
कुछ प्रकार एक प्रकार से डिस्पोजेबल संसाधनों को इनकैप्सुलेट करते हैं, जहाँ एक ही क्रिया में उनका उपयोग और निपटान करना आसान होता है। सामान्य उपयोग अक्सर इस तरह होता है: खुला, पढ़ा या लिखना, बंद (निपटान)। यह usingनिर्माण के साथ बहुत अच्छी तरह से फिट बैठता है ।
दूसरों को थोड़ा और मुश्किल होता है। WaitEventHandlesउदाहरणों के लिए इस तरह का उपयोग नहीं किया जाता है क्योंकि वे एक धागे से दूसरे में संकेत देने के लिए उपयोग किए जाते हैं। सवाल तो यह है कि Disposeइन पर किसे फोन करना चाहिए ? इस तरह के एक सुरक्षा प्रकार के रूप में Finalize, एक विधि को लागू करते हैं , जो सुनिश्चित करता है कि संसाधनों का निपटान तब किया जाता है जब उदाहरण को अनुप्रयोग द्वारा संदर्भित नहीं किया जाता है।
Finalizeउचित ठहराया जा सकता है, जब ऐसी कई वस्तुएं होती हैं जो किसी संसाधन को जीवित रखने में रुचि रखती हैं, लेकिन ऐसा कोई साधन नहीं है जिसके द्वारा संसाधन में दिलचस्पी रखने वाली कोई वस्तु पता चल सके कि क्या यह पता चल सकता है? आखरी। ऐसे मामले में, Finalizeआमतौर पर केवल तभी फायर किया जाएगा जब किसी की वस्तु में दिलचस्पी न हो। Finalizeफ़ाइलों और ताले जैसे गैर-कवक संसाधनों के लिए समय की ढीली अवधि भयानक है, लेकिन कवक संसाधनों के लिए ठीक हो सकता है।
अंतिम विधि को तब कहा जाता है जब आपकी वस्तु कचरा एकत्र की जाती है और आपको इसकी कोई गारंटी नहीं है कि ऐसा कब होगा (आप इसे बाध्य कर सकते हैं, लेकिन यह प्रदर्शन को चोट पहुंचाएगा)।
Disposeदूसरी ओर विधि कोड है कि अपने वर्ग के लिए बनाया है ताकि आप को साफ और किसी भी संसाधन (अप्रबंधित डेटा, डेटाबेस कनेक्शन, फ़ाइल हैंडल, आदि) पल कोड के साथ किया जाता आप प्राप्त कर सकते हैं जारी द्वारा कहा जा करने के लिए है आपकी वस्तु।
मानक अभ्यास को लागू करना है IDisposableऔर Disposeताकि आप किसी वस्तु में अपनी वस्तु का उपयोग कर सकें using। इस तरह के रूप में using(var foo = new MyObject()) { }। और आपके फ़ाइनलीज़र में, आप कॉल करते हैं Dispose, यदि कॉलिंग कोड आपको निपटाना भूल गया है।
अंतिम रूप एक बैकस्टॉप विधि है, जिसे कचरा कलेक्टर द्वारा बुलाया जाता है जब वह किसी वस्तु को पुनः प्राप्त करता है। निपटान "निर्धारक सफाई" विधि है, जिसे बहुमूल्य देशी संसाधनों (खिड़की के हैंडल, डेटाबेस कनेक्शन, आदि) को जारी करने के लिए अनुप्रयोगों द्वारा बुलाया जाता है, जब उन्हें अब ज़रूरत नहीं होती, बजाय उन्हें अनिश्चित काल तक पकड़े रहने के बजाय जब तक कि जीसी वस्तु के लिए गोल न हो जाए।
ऑब्जेक्ट के उपयोगकर्ता के रूप में, आप हमेशा डिस्पोज़ का उपयोग करते हैं। जीसी के लिए अंतिम रूप है।
एक वर्ग के कार्यान्वयनकर्ता के रूप में, यदि आप प्रबंधित संसाधनों को पकड़ते हैं, जिन्हें निपटाना है, तो आप निपटान को लागू करते हैं। यदि आप मूल संसाधन रखते हैं, तो आप Dispose and Finalize दोनों को कार्यान्वित करते हैं, और दोनों एक सामान्य विधि कहते हैं जो मूल संसाधनों को जारी करती है। इन मुहावरों को आम तौर पर एक निजी डिस्पोज़ल (बूल डिस्पोज़िंग) विधि के माध्यम से जोड़ा जाता है, जो कॉल को सही के साथ डिस्पोज़ करता है, और झूठी के साथ कॉल को अंतिम रूप देता है। यह विधि हमेशा मूल संसाधनों को मुक्त करती है, फिर डिस्पोज़ करने वाले पैरामीटर की जांच करती है, और यदि यह सही है तो प्रबंधित संसाधनों का निपटान करता है और GC.SuppressFinalize को कॉल करता है।
Disposeअच्छा है, और इसे सही तरीके से लागू करना आम तौर पर आसान है। Finalizeबुराई है, और इसे सही ढंग से लागू करना आम तौर पर कठिन है। अन्य बातों के अलावा, क्योंकि GC यह सुनिश्चित करेगा कि किसी भी वस्तु की पहचान को कभी "पुनर्नवीनीकरण" नहीं मिलेगा, जब तक कि उस वस्तु का कोई भी संदर्भ मौजूद नहीं है, Disposableवस्तुओं का एक गुच्छा साफ करना आसान है , जिनमें से कुछ को पहले ही साफ किया जा सकता है, कोई दिक्कत नहीं है; किसी वस्तु का कोई संदर्भ जिस Disposeपर पहले ही कॉल किया Disposeजा चुका है, उस वस्तु का संदर्भ रहेगा जिस पर पहले ही कॉल किया जा चुका है।
Fredफ़ाइल हैंडल # 42 का मालिक है और इसे बंद कर देता है, तो सिस्टम उसी नंबर को कुछ फ़ाइल हैंडल से संलग्न कर सकता है जो किसी अन्य इकाई को दिया गया है। उस स्थिति में, फ़ाइल हैंडल # 42 फ्रेड की बंद फ़ाइल को संदर्भित नहीं करेगा, लेकिन उस फ़ाइल को जो उस अन्य संस्था द्वारा सक्रिय उपयोग में थी; के लिए Fredबंद करने के # 42 संभाल कोशिश करने के लिए फिर से विनाशकारी होगा। 100% की कोशिश मज़बूती से करें कि क्या एक अप्रबंधित वस्तु को अभी तक जारी किया गया है वह व्यावहारिक है। कई वस्तुओं का ट्रैक रखने की कोशिश बहुत कठिन है।
अंतिम रूप
protectedनहीं, publicया privateकि विधि आवेदन के कोड से सीधे नहीं कहा जा सकता तो और एक ही समय में, यह करने के लिए एक कॉल कर सकते base.Finalizeविधिनिपटान
IDisposableहर प्रकार पर लागू करें जिसमें एक अंतिम रूप हैDisposeविधि को कॉल करने के बाद किसी ऑब्जेक्ट को अनुपयोगी बना दिया जाता है । दूसरे शब्दों में, इस पर Disposeविधि को बुलाए जाने के बाद किसी वस्तु का उपयोग करने से बचें ।Disposeसभी IDisposableप्रकार पर कॉल करेंDisposeत्रुटियों को उठाए बिना कई बार कॉल करने की अनुमति दें ।Disposeविधि का उपयोग कर GC.SuppressFinalizeविधि के भीतर से अंतिम रूप में कहता हैDisposeतरीकों के भीतर से अपवाद फेंकने से बचेंनिपटान / अंतिम रूप दिया गया
Disposeऔर Finalizeजब अप्रबंधित संसाधनों के साथ काम कर रहे। Finalizeकार्यान्वयन चल पाएंगे और संसाधनों अभी भी जब वस्तु कचरा भी एकत्र करता है, तो एक डेवलपर कॉल करने के लिए उपेक्षित है जारी किया जाएगा Disposeविधि स्पष्ट रूप से।Finalizeविधि के साथ-साथ Disposeविधि में अप्रबंधित संसाधनों की सफाई करें । इसके अतिरिक्त Disposeकिसी भी .NET ऑब्जेक्ट के लिए विधि को कॉल करें जो आपके पास उस वर्ग के घटक के रूप में है ( Disposeविधि के रूप में अप्रबंधित संसाधन वाले) ।जीसी द्वारा अंतिम रूप दिया जाता है जब यह ऑब्जेक्ट उपयोग में नहीं होता है।
निपटान सिर्फ एक सामान्य विधि है जिसे इस वर्ग का उपयोगकर्ता किसी भी संसाधन को जारी करने के लिए कह सकता है।
यदि उपयोगकर्ता डिसपोजल को कॉल करना भूल गया है और यदि क्लास ने अंतिम रूप से लागू किया है, तो जीसी यह सुनिश्चित कर देगा कि उसे कॉल किया जाता है।
MCSD सर्टिफिकेशन टूलकिट (परीक्षा 70-483) पृष्ठ 193 से पुस्तक के बारे में कुछ कुंजियाँ हैं:
विध्वंसक dest (यह लगभग बराबर है)base.Finalize() , विध्वंसक को अंतिम विधि के ओवरराइड संस्करण में परिवर्तित किया जाता है जो विध्वंसक कोड को निष्पादित करता है और फिर बेस क्लास के फाइनल विधि को कॉल करता है। फिर इसकी पूरी तरह से गैर-नियतात्मक आप यह जानने में सक्षम नहीं हो सकते कि कब बुलाया जाएगा क्योंकि जीसी पर निर्भर करता है।
यदि किसी वर्ग में कोई प्रबंधित संसाधन नहीं हैं और कोई अप्रबंधित संसाधन नहीं हैं , तो इसे लागू नहीं करना चाहिए IDisposableया विनाशकारी नहीं होना चाहिए ।
यदि वर्ग में केवल संसाधन हैं , तो इसे लागू करना चाहिए, IDisposableलेकिन इसमें विध्वंसक नहीं होना चाहिए। (जब विध्वंसक निष्पादित होता है, तो आप सुनिश्चित नहीं कर सकते कि प्रबंधित ऑब्जेक्ट अभी भी मौजूद हैं, इसलिए आप उनके Dispose()तरीकों को वैसे भी कॉल नहीं कर सकते ।)
यदि कक्षा में केवल अप्रबंधित संसाधन हैं , तो इसे लागू करने की आवश्यकता होती है IDisposableऔर यदि प्रोग्राम कॉल नहीं करता है , तो इसे विध्वंसक की आवश्यकता होती है Dispose()।
Dispose()विधि को एक से अधिक बार चलाने के लिए सुरक्षित होना चाहिए। आप इसे पहले चलाए जा चुके हैं या नहीं इसका ध्यान रखने के लिए एक चर का उपयोग करके प्राप्त कर सकते हैं।
Dispose()प्रबंधित और अप्रबंधित दोनों संसाधनों को मुक्त करना चाहिए ।
विध्वंसक को केवल मानव रहित संसाधनों को मुक्त करना चाहिए । जब विध्वंसक निष्पादित होता है, तो आप सुनिश्चित नहीं कर सकते कि प्रबंधित वस्तुएं अभी भी मौजूद हैं, इसलिए आप उनके निपटान के तरीकों को वैसे भी नहीं कह सकते। यह विहित protected void Dispose(bool disposing)पैटर्न का उपयोग करके प्राप्त किया जाता है , जहां केवल प्रबंधित संसाधनों को मुक्त किया जाता है (जब निपटाया जाता है) disposing == true।
संसाधनों को मुक्त करने के बाद, Dispose()कॉल करना चाहिएGC.SuppressFinalize , इसलिए ऑब्जेक्ट अंतिम रूप कतार को छोड़ सकता है।
मानव रहित और प्रबंधित संसाधनों वाले वर्ग के लिए कार्यान्वयन का एक उदाहरण:
using System;
class DisposableClass : IDisposable
{
// A name to keep track of the object.
public string Name = "";
// Free managed and unmanaged resources.
public void Dispose()
{
FreeResources(true);
// We don't need the destructor because
// our resources are already freed.
GC.SuppressFinalize(this);
}
// Destructor to clean up unmanaged resources
// but not managed resources.
~DisposableClass()
{
FreeResources(false);
}
// Keep track if whether resources are already freed.
private bool ResourcesAreFreed = false;
// Free resources.
private void FreeResources(bool freeManagedResources)
{
Console.WriteLine(Name + ": FreeResources");
if (!ResourcesAreFreed)
{
// Dispose of managed resources if appropriate.
if (freeManagedResources)
{
// Dispose of managed resources here.
Console.WriteLine(Name + ": Dispose of managed resources");
}
// Dispose of unmanaged resources here.
Console.WriteLine(Name + ": Dispose of unmanaged resources");
// Remember that we have disposed of resources.
ResourcesAreFreed = true;
}
}
}
99% समय, आपको इसके बारे में चिंता करने की आवश्यकता नहीं होनी चाहिए। :) लेकिन, यदि आपकी वस्तुएँ गैर-प्रबंधित संसाधनों (विंडो हैंडल, फ़ाइल हैंडल, उदाहरण के लिए) के संदर्भ रखती हैं, तो आपको उन संसाधनों को जारी करने के लिए अपने प्रबंधित ऑब्जेक्ट के लिए एक तरीका प्रदान करने की आवश्यकता है। अंतिम रूप संसाधनों को जारी करने पर अंतर्निहित नियंत्रण देता है। इसे कचरा संग्राहक कहा जाता है। निपटान संसाधनों की रिहाई पर स्पष्ट नियंत्रण देने का एक तरीका है और इसे सीधे कहा जा सकता है।
कचरा संग्रह के विषय के बारे में जानने के लिए बहुत कुछ है , लेकिन यह एक शुरुआत है।
फ़ाइनलीज़र निहित सफाई के लिए है - आपको इसका उपयोग तब करना चाहिए जब कोई वर्ग संसाधनों का प्रबंधन करता है जिसे बिल्कुल साफ किया जाना चाहिए अन्यथा आप हैंडल / मेमोरी आदि को लीक कर देंगे ...
सही ढंग से एक अंतिम रूप से लागू करना बहुत मुश्किल है और जहाँ भी संभव हो SafeHandleउससे बचा जाना चाहिए - वर्ग (avaialble in .Net v2.0 और इसके बाद के संस्करण) का मतलब है कि अब आप शायद ही कभी (यदि कभी भी) को अंतिम रूप से लागू करने की आवश्यकता है।
IDisposableइंटरफ़ेस स्पष्ट सफाई के लिए है और भी बहुत कुछ आमतौर पर इस्तेमाल किया जाता है - आप इस का उपयोग करना चाहिए उपयोगकर्ताओं को स्पष्ट रूप से जारी या सफाई संसाधनों जब भी वे एक वस्तु का उपयोग कर समाप्त कर दिया है करने के लिए अनुमति देने के लिए।
ध्यान दें कि यदि आपके पास एक अंतिम रूप है, तो आपको IDisposableइंटरफ़ेस को भी लागू करना चाहिए ताकि उपयोगकर्ताओं को स्पष्ट रूप से उन संसाधनों को जल्द से जल्द जारी करने की अनुमति मिल सके, जब वस्तु एकत्र की गई थी।
डीजी अपडेट देखें : मैं जो भी अंतिम और सलाहकारों पर सिफारिशों का सबसे अच्छा और सबसे पूरा सेट मानता हूं, उसके लिए निपटान, अंतिमकरण, और संसाधन प्रबंधनIDisposable ।
सारांश है -
इसके अलावा, एक और अंतर है - डिस्पोज़ () कार्यान्वयन में, आपको प्रबंधित संसाधनों को भी जारी करना चाहिए , जबकि फाइनल में ऐसा नहीं किया जाना चाहिए। ऐसा इसलिए है क्योंकि यह संभावना है कि ऑब्जेक्ट द्वारा संदर्भित प्रबंधित संसाधन अंतिम रूप से तैयार होने से पहले ही साफ हो गए हैं।
एक ऐसे वर्ग के लिए जो अप्रबंधित संसाधनों का उपयोग करता है, सबसे अच्छा अभ्यास दोनों को परिभाषित करना है - डिस्पोज़ () विधि और फ़ाइनलीज़र - का उपयोग उस स्थिति में किया जाता है जब कोई डेवलपर ऑब्जेक्ट को हटाने के लिए भूल जाता है। दोनों प्रबंधित और अप्रबंधित संसाधनों को साफ करने के लिए एक साझा विधि का उपयोग कर सकते हैं: -
class ClassWithDisposeAndFinalize : IDisposable
{
// Used to determine if Dispose() has already been called, so that the finalizer
// knows if it needs to clean up unmanaged resources.
private bool disposed = false;
public void Dispose()
{
// Call our shared helper method.
// Specifying "true" signifies that the object user triggered the cleanup.
CleanUp(true);
// Now suppress finalization to make sure that the Finalize method
// doesn't attempt to clean up unmanaged resources.
GC.SuppressFinalize(this);
}
private void CleanUp(bool disposing)
{
// Be sure we have not already been disposed!
if (!this.disposed)
{
// If disposing equals true i.e. if disposed explicitly, dispose all
// managed resources.
if (disposing)
{
// Dispose managed resources.
}
// Clean up unmanaged resources here.
}
disposed = true;
}
// the below is called the destructor or Finalizer
~ClassWithDisposeAndFinalize()
{
// Call our shared helper method.
// Specifying "false" signifies that the GC triggered the cleanup.
CleanUp(false);
}
सबसे अच्छा उदाहरण जो मुझे पता है।
public abstract class DisposableType: IDisposable
{
bool disposed = false;
~DisposableType()
{
if (!disposed)
{
disposed = true;
Dispose(false);
}
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
}
public void Close()
{
Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// managed objects
}
// unmanaged objects and resources
}
}
C # में अंतिम रूप और निपटान के तरीकों के बीच का अंतर।
जीसी अनवांटेड रिसोर्सेज (जैसे कि फाइल ऑपरेट, विंडोज एपि, नेटवर्क कनेक्शन, डेटाबेस कनेक्शन) को रिकॉल करने के लिए अंतिम विधि को कॉल करता है, लेकिन जब जीसी इसे कॉल करेगा, तो समय तय नहीं है। इसे जीसी द्वारा निहित रूप से कहा जाता है इसका मतलब है कि हमारे पास इस पर निम्न स्तर का नियंत्रण नहीं है।
डिस्पोज़ मेथड: कोड से कॉल करने पर हमारा उस पर निम्न स्तर का नियंत्रण होता है। जब भी हमें लगता है कि यह प्रयोग करने योग्य नहीं है, तो हम अप्रबंधित संसाधनों को पुनः प्राप्त कर सकते हैं। हम इसे आईडीसपोजिशन पैटर्न लागू करके प्राप्त कर सकते हैं।
क्लास इंस्टेंसेस अक्सर उन संसाधनों पर नियंत्रण को ध्वस्त कर देते हैं जिन्हें रनटाइम द्वारा प्रबंधित नहीं किया जाता है, जैसे कि विंडो हैंडल (HWND), डेटाबेस कनेक्शन, और इसी तरह। इसलिए, आपको उन संसाधनों को मुक्त करने के लिए एक स्पष्ट और अंतर्निहित तरीका प्रदान करना चाहिए। किसी ऑब्जेक्ट पर संरक्षित अंतिम विधि (C # में विध्वंसक सिंटैक्स और ++ के लिए प्रबंधित एक्सटेंशन) को लागू करके अंतर्निहित नियंत्रण प्रदान करें। कचरा संग्रहकर्ता किसी बिंदु पर इस विधि को कॉल करता है, जिसके बाद वस्तु का कोई वैध संदर्भ नहीं रह जाता है। कुछ मामलों में, आप प्रोग्रामर को ऑब्जेक्ट का उपयोग करने की क्षमता के साथ इन बाहरी संसाधनों को स्पष्ट रूप से जारी करने की क्षमता प्रदान करने से पहले प्रोग्रामर प्रदान करना चाह सकते हैं। यदि बाहरी संसाधन दुर्लभ या महंगा है, तो बेहतर प्रदर्शन प्राप्त किया जा सकता है यदि प्रोग्रामर स्पष्ट रूप से संसाधनों को जारी करता है जब उनका उपयोग नहीं किया जाता है। सुस्पष्ट नियंत्रण प्रदान करने के लिए, आईडीसोप्लॉरी इंटरफ़ेस द्वारा प्रदान की गई डिस्पोज़ विधि को लागू करें। ऑब्जेक्ट के उपभोक्ता को इस विधि को कॉल करना चाहिए जब यह ऑब्जेक्ट का उपयोग करके किया जाता है। वस्तु के अन्य संदर्भ जीवित होने पर भी निपटान को कहा जा सकता है।
ध्यान दें कि जब आप निपटान के माध्यम से स्पष्ट नियंत्रण प्रदान करते हैं, तो आपको अंतिम विधि का उपयोग करके अंतर्निहित सफाई प्रदान करनी चाहिए। अंतिम रूप से प्रोग्रामर को कॉल करने में विफल रहने पर संसाधनों को स्थायी रूप से लीक होने से रोकने के लिए एक बैकअप प्रदान करता है।
Dispose और Finalize के बीच मुख्य अंतर यह है कि:
Disposeआमतौर पर आपके कोड द्वारा बुलाया जाता है। जब आप इसे कहते हैं तो संसाधन तुरंत मुक्त हो जाते हैं। लोग विधि को कॉल करना भूल जाते हैं, इसलिए using() {}कथन का आविष्कार किया जाता है। जब आपका प्रोग्राम अंदर कोड का निष्पादन समाप्त कर देता है {}, तो यह Disposeस्वचालित रूप से कॉल विधि होगी ।
Finalizeआपके कोड द्वारा नहीं बुलाया जाता है। यह कचरा कलेक्टर (जीसी) द्वारा बुलाया जाना है। इसका मतलब है कि जब भी जीसी ऐसा करने का फैसला करेगा, भविष्य में संसाधन को कभी भी मुक्त किया जा सकता है। जब GC अपना काम करता है, तो यह कई अंतिम तरीकों से गुजरेगा। यदि आपके पास इसमें भारी तर्क हैं, तो यह प्रक्रिया को धीमा कर देगा। यह आपके प्रोग्राम के लिए प्रदर्शन समस्याओं का कारण हो सकता है। इसलिए इस बारे में सावधान रहें कि आपने वहां क्या रखा है।
मैं व्यक्तिगत रूप से डिस्पोज़ में अधिकांश विनाश तर्क लिखूंगा। उम्मीद है, यह भ्रम को साफ करता है।
जैसा कि हम जानते हैं कि निपटाने और अंतिम रूप देने के लिए दोनों का उपयोग अप्रबंधित संसाधनों को मुक्त करने के लिए किया जाता है .. लेकिन अंतर को अंतिम रूप दिया जाता है दो संसाधनों का उपयोग करने के लिए, जहां निपटान एक चक्र का उपयोग करता है।
पहले भाग पर जवाब देने के लिए आपको ऐसे उदाहरण उपलब्ध कराने चाहिए जहाँ लोग एक ही कक्षा-वस्तु के लिए अलग-अलग दृष्टिकोण का उपयोग करते हैं। अन्यथा जवाब देना मुश्किल (या अजीब भी) है।
दूसरे प्रश्न के रूप में बेहतर पढ़ने के लिए सबसे पहले आइडीसोपायरी इंटरफ़ेस का यह उचित उपयोग करें जो दावा करता है कि
यह तुम्हारी पसंद है! लेकिन डिस्पोजल चुनें।
दूसरे शब्दों में: जीसी केवल फाइनलिज़र के बारे में जानता है (यदि कोई हो। इसे माइक्रोसॉफ्ट के विनाशकर्ता के रूप में भी जाना जाता है)। एक अच्छा कोड दोनों (फाइनल और डिस्पोज़) से सफाई का प्रयास करेगा।