नई वस्तु बनाएं या हर संपत्ति को रीसेट करें?


29
 public class MyClass
    {
        public object Prop1 { get; set; }

        public object Prop2 { get; set; }

        public object Prop3 { get; set; }
    }

मान लीजिए कि मेरे पास एक वस्तु myObjectहै MyClassऔर मुझे इसके गुणों को रीसेट करने की आवश्यकता है, क्या नई वस्तु बनाना बेहतर है या प्रत्येक संपत्ति को फिर से असाइन करना है? मान लें कि मेरे पास पुराने उदाहरण के साथ कोई अतिरिक्त उपयोग नहीं है।

myObject = new MyClass();

या

myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;


14
वास्तव में संदर्भ के बिना जवाब नहीं दिया जा सकता।
कोडइंचोज

2
@CodesInChaos, वास्तव में। विशिष्ट उदाहरण जिसमें नई वस्तुएं बनाना बेहतर नहीं हो सकता है: ऑब्जेक्ट पूलिंग और जीसी से निपटने के लिए आवंटन को कम करने का प्रयास।
XNargaHuntress

@ XGundam05 लेकिन फिर भी, यह बहुत संभावना नहीं है कि ओपी में सुझाई गई यह तकनीक इससे निपटने का उपयुक्त तरीका है
बेन आरोनसन

2
Suppose I have an object myObject of MyClass and I need to reset its properties- यदि आपके ऑब्जेक्ट के गुणों को रीसेट करना आवश्यक है या यदि यह समस्या डोमेन को मॉडल करने के लिए उपयोगी है, तो reset()MyClass के लिए एक विधि क्यों न बनाएं । नीचे
हैरिसनपिन

जवाबों:


49

एक नई वस्तु को तुरंत बनाना हमेशा बेहतर होता है, तो आपके पास गुण (निर्माणकर्ता) को इनिशियलाइज़ करने के लिए 1 जगह होती है और इसे आसानी से अपडेट कर सकते हैं।

कल्पना कीजिए कि आप क्लास में एक नई प्रॉपर्टी जोड़ते हैं, आप कंस्ट्रक्टर को अपडेट करने के बजाय एक नया तरीका जोड़ते हैं जो सभी प्रॉपर्टीज को फिर से इनिशियलाइज करता है।

अब, ऐसे मामले हैं जहां आप किसी वस्तु का फिर से उपयोग करना चाहते हैं, जहां एक संपत्ति को फिर से शुरू करने के लिए बहुत महंगा है और आप इसे रखना चाहते हैं। हालांकि यह अधिक विशेषज्ञ होगा, और आपके पास अन्य सभी गुणों को फिर से संगठित करने के लिए विशेष तरीके होंगे। आप इस स्थिति के लिए भी कभी-कभी एक नई वस्तु बनाना चाहते हैं।


6
संभावित तीसरा विकल्प myObject = new MyClass(oldObject);:। हालांकि यह नए उदाहरण में मूल वस्तु की एक सटीक प्रति होगी।
AmazingDreams

मुझे लगता new MyClass(oldObject)है कि उन मामलों के लिए सबसे अच्छा समाधान है जहां आरंभीकरण महंगा है।
rickcnagy

8
प्रतिलिपि बनाने वाले अधिक C ++ शैली के हैं। .NET एक क्लोन () पद्धति का पक्ष लेता है जो एक नया उदाहरण देता है जो एक सटीक प्रतिलिपि है।
एरिक

2
कंस्ट्रक्टर आसानी से कुछ भी नहीं कर सकता है, लेकिन एक पब्लिक इनिशियलाइज़ () विधि को कॉल कर सकता है ताकि आपके पास अभी भी इनिशियलाइज़ेशन का एक बिंदु हो जो किसी भी बिंदु को प्रभावी रूप से "नई" ताज़ा ऑब्जेक्ट बनाने के लिए आमंत्रित किया जा सके। मैंने उन पुस्तकालयों का उपयोग किया है जिनमें ऑब्जेक्ट के लिए IInitialize इंटरफ़ेस जैसा कुछ है जो ऑब्जेक्ट पूल में उपयोग किया जा सकता है और प्रदर्शन के लिए पुन: उपयोग किया जा सकता है।
चाड शाउगिन्स

16

आपको निश्चित रूप से अधिकांश मामलों में एक नई वस्तु बनाना पसंद करना चाहिए । सभी गुणों को पुन: पेश करने में समस्याएं:

  • सभी संपत्तियों पर सार्वजनिक निपटान की आवश्यकता होती है, जो आपके द्वारा प्रदान किए जाने वाले एनकैप्सुलेशन के स्तर को काफी सीमित कर सकता है
  • यह जानना कि क्या आपके पास पुराने उदाहरण के लिए कोई अतिरिक्त उपयोग है या नहीं, इसका मतलब है कि आपको हर जगह यह जानना होगा कि पुराने उदाहरण का उपयोग किया जा रहा है। इसलिए यदि वर्ग Aऔर वर्ग Bदोनों ही वर्ग के उत्तीर्ण उदाहरण हैंC तो उन्हें यह जानना होगा कि क्या वे कभी भी एक ही उदाहरण से उत्तीर्ण होंगे, और यदि ऐसा है तो क्या दूसरा अभी भी इसका उपयोग कर रहा है। यह कसकर जोड़े वर्गों जो अन्यथा होने का कोई कारण नहीं है।
  • बार-बार कोड की ओर जाता है- जैसा कि gbjbaanb ने संकेत दिया है, यदि आप कंस्ट्रक्टर में एक पैरामीटर जोड़ते हैं, तो हर जगह जो कॉल करता है कि कंस्ट्रक्टर संकलित करने में विफल हो जाएगा, स्पॉट के लापता होने का कोई खतरा नहीं है। यदि आप केवल एक सार्वजनिक संपत्ति जोड़ते हैं, तो आपको हर उस जगह को मैन्युअल रूप से ढूंढना और अद्यतन करना होगा जहां ऑब्जेक्ट "रीसेट" हैं।
  • जटिलता बढ़ाता है। कल्पना कीजिए कि आप लूप में कक्षा का एक उदाहरण बना रहे हैं और उसका उपयोग कर रहे हैं। यदि आप अपनी विधि का उपयोग करते हैं, तो आपको अब लूप के माध्यम से या लूप शुरू होने से पहले अलग-अलग इनिशियलाइज़ेशन करना होगा। किसी भी तरह से अतिरिक्त कोड है जिसे आपको प्रारंभ करने के इन दो तरीकों का समर्थन करने के लिए लिखना होगा।
  • इसका मतलब है कि आपकी कक्षा खुद को अमान्य स्थिति में होने से नहीं बचा सकती। कल्पना कीजिए कि आपने Fractionएक अंश और हर के साथ एक वर्ग लिखा था, और यह लागू करना चाहता था कि यह हमेशा कम हो गया (यानी अंश और भाजक का एलसीडी 1 था)। यह अच्छी तरह से करना असंभव है यदि आप लोगों को अंश और भाजक को सार्वजनिक रूप से सेट करने की अनुमति देना चाहते हैं, क्योंकि वे एक वैध राज्य से दूसरे को प्राप्त करने के लिए अमान्य राज्य के माध्यम से संक्रमण कर सकते हैं। उदा 1/2 (वैध) -> 2/2 (अमान्य) -> 2/3 (वैध)।
  • जिस भाषा में आप काम कर रहे हैं, उसके लिए बिल्कुल भी मुहावरेदार नहीं है, कोड को बनाए रखने वाले किसी व्यक्ति के लिए संज्ञानात्मक घर्षण बढ़ाना।

ये सभी बहुत महत्वपूर्ण समस्याएं हैं। और आपके द्वारा बनाए गए अतिरिक्त काम के बदले में आपको क्या मिलता है ... कुछ भी नहीं। वस्तुओं के उदाहरणों को बनाना, सामान्य रूप से, अविश्वसनीय रूप से सस्ता है, इसलिए प्रदर्शन लाभ लगभग हमेशा पूरी तरह से नगण्य होगा।

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


एक तरफ ध्यान दें के रूप में, कुछ ऊपर समस्याओं की setters का उपयोग नहीं है और इसके बजाय एक होने से कुछ हद तक कम किया जा सकताpublic Reset है, जिसमें निर्माता के रूप में ही पैरामीटर लेता है अपनी कक्षा पर विधि। यदि किसी कारण से आप इस रीसेट मार्ग से नीचे जाना चाहते हैं, तो संभवतः यह करने का एक बेहतर तरीका होगा।

फिर भी, अतिरिक्त जटिलता और दोहराव, जो ऊपर दिए गए बिंदुओं के साथ जोड़ता है, यह अभी भी इसे करने के खिलाफ एक बहुत ही प्रेरक तर्क नहीं है, खासकर जब बिना किसी लाभ के खिलाफ तौला जाता है।


मुझे लगता है कि नई वस्तु बनाने के बजाय रीसेट करने के लिए एक बहुत ही महत्वपूर्ण महत्वपूर्ण उपयोग मामला है यदि आप वास्तव में ऑब्जेक्ट को रीसेट कर रहे हैं। अर्थात। यदि आप अन्य कक्षाएं चाहते हैं जो ऑब्जेक्ट को आपके रीसेट के बाद एक ताज़ा ऑब्जेक्ट देखने के लिए इंगित करें।
तैमूर

@ तायमेय संभवतः, लेकिन ओपी स्पष्ट रूप से नियम है कि सवाल में बाहर
बेन आरोनसन

9

बहुत ही सामान्य उदाहरण को देखते हुए, यह बताना मुश्किल है। यदि "गुणों को रीसेट करना" डोमेन के मामले में शब्दार्थ समझ में आता है, तो यह आपके वर्ग के उपभोक्ता को कॉल करने के लिए अधिक समझ में आएगा।

MyObject.Reset(); // Sets all necessary properties to null

से

MyObject = new MyClass();

मुझे आपके वर्ग कॉल के उपभोक्ता बनाने की आवश्यकता नहीं होगी

MyObject.Prop1 = null;
MyObject.Prop2 = null; // and so on

यदि क्लास किसी ऐसी चीज़ का प्रतिनिधित्व करता है, जिसे रीसेट किया जा सकता है, तो उसे उस कार्यप्रणाली को एक Reset()विधि के माध्यम से उजागर करना चाहिए , न कि निर्माणकर्ता को कॉल करने या मैन्युअल रूप से उसके गुणों को सेट करने के लिए।


5

जैसा कि हैरिसन पाइन और ब्रैंडिन सुझाव देते हैं, मैं उसी वस्तु का फिर से उपयोग करूंगा और रेसिपी विधि में गुणों के आरंभ का गुणन करूंगा:

public class MyClass
{
    public MyClass() { this.Reset() }

    public void Reset() {
        this.Prop1 = whatever
        this.Prop2 = you name it
        this.Prop3 = oh yeah
    }

    public object Prop1 { get; set; }

    public object Prop2 { get; set; }

    public object Prop3 { get; set; }
}

बिल्कुल वही जो मैं जवाब देना चाहता था। यह दोनों दुनिया में सबसे अच्छा है - और उपयोग के मामले पर निर्भर करता है, एकमात्र व्यवहार्य विकल्प (इंस्टेंस-पूलिंग)
फाल्को

2

यदि किसी वर्ग के लिए इरादा उपयोग पैटर्न यह है कि एक एकल स्वामी प्रत्येक उदाहरण के लिए एक संदर्भ रखेगा, कोई अन्य कोड संदर्भों की प्रतियां नहीं रखेगा, और मालिकों के लिए लूप होना बहुत आम बात होगी, जिसकी आवश्यकता कई बार होती है , " "एक रिक्त उदाहरण भरें, इसे अस्थायी रूप से उपयोग करें, और इसे फिर कभी ज़रूरत नहीं है (एक सामान्य वर्ग की बैठक ऐसी कसौटी होगी StringBuilder) तो यह वर्ग के लिए एक प्रदर्शन के दृष्टिकोण से उपयोगी हो सकता है, जैसे उदाहरण को रीसेट करने के लिए एक विधि को शामिल करना- नई शर्त। इस तरह के अनुकूलन की बहुत अधिक संभावना नहीं है यदि विकल्प को केवल कुछ सौ उदाहरण बनाने की आवश्यकता होगी, लेकिन लाखों या अरबों ऑब्जेक्ट इंस्टेंसेस बनाने की लागत बढ़ सकती है।

संबंधित नोट पर, कुछ पैटर्न हैं जो उन तरीकों के लिए उपयोग किए जा सकते हैं, जिन्हें किसी ऑब्जेक्ट में डेटा वापस करने की आवश्यकता होती है:

  1. विधि नई वस्तु बनाती है; संदर्भ देता है।

  2. विधि एक उत्परिवर्तनीय वस्तु के संदर्भ को स्वीकार करती है, और इसे भरती है।

  3. विधि एक संदर्भ-प्रकार के चर को एक refपैरामीटर के रूप में स्वीकार करती है और या तो उपयुक्त होने पर मौजूदा वस्तु का उपयोग करती है, या एक नई वस्तु की पहचान करने के लिए चर को बदलती है।

पहला दृष्टिकोण अक्सर सबसे आसान शब्दार्थ है। दूसरा कॉलिंग साइड में थोड़ा अजीब है, लेकिन बेहतर प्रदर्शन की पेशकश कर सकता है अगर एक कॉल करने वाला अक्सर एक ऑब्जेक्ट बनाने और हजारों बार उपयोग करने में सक्षम होगा। तीसरा दृष्टिकोण थोड़ा अजीब है, लेकिन सहायक हो सकता है अगर किसी विधि को किसी सरणी में डेटा वापस करने की आवश्यकता होगी और कॉलर को आवश्यक सरणी आकार नहीं पता होगा। यदि कॉलिंग कोड सरणी के लिए एकमात्र संदर्भ रखता है, तो उस संदर्भ को एक बड़े सरणी के संदर्भ में फिर से लिखना, शब्दार्थ को केवल सरणी को बड़ा बनाने के बराबर होगा (जो कि वांछित व्यवहार शब्दार्थ है)। उपयोग करते समय List<T>कई मामलों में मैन्युअल रूप से आकार दिए गए सरणी का उपयोग करने से अच्छा हो सकता है, संरचनाओं की सरणियाँ संरचनाओं की सूचियों की तुलना में बेहतर शब्दार्थ और बेहतर प्रदर्शन प्रदान करती हैं।


1

मुझे लगता है कि एक नई वस्तु बनाने के पक्ष में जवाब देने वाले अधिकांश लोग एक महत्वपूर्ण परिदृश्य को याद कर रहे हैं: कचरा संग्रह (जीसी)। जीसी अनुप्रयोगों में एक वास्तविक प्रदर्शन हिट हो सकता है जो बहुत सारी वस्तुओं का निर्माण करता है (गेम, या वैज्ञानिक अनुप्रयोग)।

मान लें कि मेरे पास एक अभिव्यक्ति ट्री है जो गणितीय अभिव्यक्ति का प्रतिनिधित्व करता है, जहां आंतरिक नोड्स फ़ंक्शन नोड्स (ADD, SUB, MUL, DIV) हैं, और लीफ नोड्स टर्मिनल नोड्स (एक्स, ई, पीआई) हैं। यदि मेरे नोड वर्ग का मूल्यांकन () विधि है, तो यह संभवतः बच्चों पर पुनरावर्ती कॉल करेगा और डेटा नोड के माध्यम से डेटा एकत्र करेगा। बहुत कम से कम, सभी पत्तों के नोड्स को एक डेटा ऑब्जेक्ट बनाने की आवश्यकता होगी और फिर अंतिम मूल्य का मूल्यांकन होने तक वे पेड़ के रास्ते पर फिर से उपयोग कर सकते हैं।

अब हम कहते हैं कि मेरे पास इनमें से हजारों पेड़ हैं और मैं उनका मूल्यांकन एक पाश में करता हूं। उन सभी डेटा ऑब्जेक्ट्स GC को ट्रिगर करने जा रहे हैं और एक प्रदर्शन हिट का कारण बनता है, मेरे ऐप में कुछ रनों के लिए एक बड़ा एक (40% तक सीपीयू उपयोग नुकसान - मैंने डेटा प्राप्त करने के लिए एक प्रोफाइलर चलाया है)।

एक संभव समाधान? उन डेटा ऑब्जेक्ट्स का पुनः उपयोग करें और बस कुछ का उपयोग करें। () उन पर उपयोग करने के बाद आप उन पर काम करें। लीफ नोड्स अब 'नया डेटा ()' नहीं कहेंगे, वे कुछ फ़ैक्टरी विधि को कॉल करेंगे जो ऑब्जेक्ट के जीवनचक्र को संभालती है।

मुझे यह पता है क्योंकि मेरे पास एक आवेदन है जिसने इस मुद्दे को मारा है और इसने इसे हल किया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.