C # में "कांस्ट शुद्धता"


79

Const-correctness का बिंदु एक ऐसे उदाहरण को देखने में सक्षम होना है जो उपयोगकर्ता द्वारा परिवर्तित या हटाया नहीं जा सकता है। कंपाइलर इस बात का समर्थन करता है कि जब आप किसी कॉस्ट फंक्शन के भीतर से कॉन्स्टिपेशन को तोड़ते हैं, या किसी कॉन्सेंट ऑब्जेक्ट के नॉन-कॉस्ट फ़ंक्शन का उपयोग करने का प्रयास करते हैं। तो कॉन्स्टल एप्रोच को कॉपी किए बिना, क्या कोई कार्यप्रणाली है जिसका उपयोग मैं C # में कर सकता हूं जिसमें समान छोर हैं?

मैं अपरिवर्तनीयता से अवगत हूं, लेकिन यह वास्तव में कंटेनर वस्तुओं को नाम देने के लिए नहीं ले जाता है, लेकिन एक उदाहरण है।



फिर const_castC # में लागू करने के बारे में क्या ?
केरम

जवाबों:


64

मैं इस मुद्दे पर बहुत बार आया हूं और इंटरफेस का उपयोग करके समाप्त हुआ हूं।

मुझे लगता है कि यह विचार छोड़ना महत्वपूर्ण है कि C # किसी भी रूप, या C ++ का भी विकास है। वे दो अलग-अलग भाषाएं हैं जो लगभग एक ही वाक्यविन्यास साझा करती हैं।

मैं आमतौर पर एक कक्षा के केवल पढ़ने के दृष्टिकोण को परिभाषित करके C # में 'कांस्ट शुद्धता' व्यक्त करता हूं:

public interface IReadOnlyCustomer
{
    String Name { get; }
    int Age { get; }
}

public class Customer : IReadOnlyCustomer
{
    private string m_name;
    private int m_age;

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        set { m_age = value; }
    }
}

12
ज़रूर, लेकिन क्या होगा अगर आपका कोई एक क्षेत्र एक सूची, या एक समृद्ध प्रकार है। आपका समाधान बहुत जल्दी जटिल हो जाता है।
मैट क्रूशांक

12
@ ट्रैप: यह सवाल का पूरा बिंदु है। एक आंतरिक संग्रह लौटना एक बुरा अभ्यास है क्योंकि बाहरी दुनिया आपके आंतरिक हिस्से को संशोधित कर सकती है, सी ++ में जो कि कॉन्स्ट के उपयोग से हल किया गया है: आप संग्रह का एक निरंतर दृश्य प्रदान करते हैं (तत्वों को जोड़ / हटा नहीं सकते हैं, केवल इसके निरंतर दृश्य प्रदान करते हैं तत्व) और इस तरह यह सुरक्षित है (और एक सामान्य मुहावरा)। बाहर के कोड को अपने इंटर्नल को बदलने से बचने के लिए किसी इंटरफेस या अन्य ट्रिक पर काम करने की आवश्यकता नहीं है।
डेविड रोड्रिगेज -

9
@ लपेटें, मैं मानता हूं कि तंत्र विकास के लिए एक सहायता है जिसमें डेवलपर्स से त्रुटियों का पता लगाना शामिल है, अनुभवी या नहीं। मैं असहमत हूं कि केवल-पढ़ने के लिए इंटरफेस लिखना कई आधारों में बेहतर समाधान है। पहला बिंदु यह है कि जब भी आप C ++ में एक क्लास लिख रहे होते हैं तो आप निरंतर इंटरफ़ेस को परिभाषित कर रहे होते हैं: सदस्यों के सबसेट को constअलग इंटरफ़ेस को परिभाषित करने की अतिरिक्त लागत के बिना और रनटाइम डिस्पैच की आवश्यकता होती है। यही है, भाषा संकलन-समय की बाधा-इंटरफेस को लागू करने का एक सरल तरीका प्रदान करती है।
डेविड रॉड्रिग्ज - ड्रिबेस्स

10
यह ध्यान रखना महत्वपूर्ण है कि const-ness डिजाइन का हिस्सा है और यह बाहरी कॉन्स्टिट्यूशन-इंटरफ़ेस को लिखने के रूप में स्पष्ट रूप से इरादे की घोषणा करता है। साथ ही, अगर इसे मैन्युअल रूप से निपटना पड़ता है, तो कॉन्स्ट-इंटरफेस प्रदान करना एक जटिल काम हो सकता है, और इसमें लगभग इंटरफेस की आवश्यकता हो सकती है क्योंकि कक्षाएं कंपाउंड प्रकार में मौजूद होती हैं। यह हमें आपके अंतिम प्रेषण पर ले जाता है: 'चीजों को जोड़ने के लिए कसना जोड़ने के लिए भूल जाओ'। constहर वर्ग के लिए केवल-पढ़ने के लिए इंटरफेस लिखने की तुलना में हर जगह (विकास लागत कम है) को जोड़ना आसान है ।
डेविड रॉड्रिग्ज - ड्रिबेस्स

9
जिन कारणों से मुझे वास्तव में C # पसंद आया, उनमें से एक यह था कि यह जावा की तरह C ++ की सभी व्यावहारिक विशेषताओं को बाहर नहीं करता था। जावा ने इंटरफेस के साथ सब कुछ करने की कोशिश की, और यह एक आपदा थी। साक्ष्य पुडिंग में है। समय के साथ जावा में "बैक" में बहुत सारी सुविधाएँ जोड़ी गई हैं जिन्हें मूल रूप से विधर्मी के रूप में दर्शाया गया था। इंटरफ़ेस-आधारित डिज़ाइन में यह जगह है, लेकिन जब चरम सीमा पर ले जाया जाता है तो यह अनावश्यक रूप से एक कार्यक्रम की वास्तुकला को जटिल बना सकता है। आप बॉयलरप्लेट कोड लिखने में अधिक समय लगाते हैं और कम समय में उपयोगी सामान प्राप्त करते हैं।
kgriffs

29

कॉन्स्ट-क्रेज़नेस (या फ़ंक्शनल प्रोग्रामिंग शब्दों में शुद्धता) का लाभ पाने के लिए, आपको अपनी कक्षाओं को इस तरह से डिज़ाइन करने की आवश्यकता होगी, ताकि वे अपरिवर्तनीय हों, ठीक उसी तरह जैसे कि स्ट्रिंग # की सी क्लास है।

यह तरीका केवल एक वस्तु को आसानी से चिह्नित करने से बेहतर है, क्योंकि अपरिवर्तनीय वर्गों के साथ आप मल्टी-टास्किंग वातावरण में आसानी से डेटा पास कर सकते हैं।


8
लेकिन अपरिवर्तनीयता वास्तव में जटिल वस्तुओं का पैमाना नहीं है, या यह नहीं है?
दसवें

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

2
मुझे लगता है कि यह एक सबसे अच्छा समूह है। अपरिवर्तनीय वस्तुओं का उपयोग बहुत बार किया जाता है।

3
केवल इतना ही नहीं, बल्कि ऐसे मामले भी होते हैं, जहाँ आप चाहते हैं कि बदलती हुई वस्तुएं (ऑब्जेक्ट्स चेंज हों!) हों, लेकिन फिर भी ज्यादातर मामलों में केवल एक रीडिंग देखें। अपरिवर्तनीय वस्तुओं का अर्थ है कि जब भी आपको कोई परिवर्तन करने की आवश्यकता होती है (परिवर्तन होता है) तो आपको परिवर्तन के अलावा सभी समान डेटा के साथ एक नई वस्तु बनाने की आवश्यकता होगी। एक ऐसे स्कूल पर विचार करें, जिसमें स्कूल के कमरे हैं, छात्र हैं ... क्या आप हर बार एक नया स्कूल बनाना चाहते हैं, जब किसी छात्र की जन्मतिथि बदल जाती है और उसकी उम्र बदल जाती है? या आप सिर्फ छात्र स्तर पर छात्र को, कमरे के स्तर पर, स्कूल स्तर पर शायद कमरे को बदल सकते हैं?
डेविड रॉड्रिग्ज - dribeas

8
@tenpn: जब वास्तव में सही किया जाता है, तो अविश्वसनीयता वास्तव में अच्छी तरह से तराजू होती है। एक चीज जो वास्तव में मदद करती है वह है Builderबड़े अपरिवर्तनीय प्रकारों के लिए कक्षाओं का उपयोग (जावा और .NET उस StringBuilderवर्ग को परिभाषित करते हैं जो सिर्फ एक उदाहरण है)।
कोनराड रुडोल्फ

24

मैं सिर्फ आपके लिए यह नोट करना चाहता था कि कई System.Collections.Generics कंटेनरों में एक AsReadOnly विधि है जो आपको एक अपरिवर्तनीय संग्रह वापस देगी।


4
यह अभी भी मुद्दा है कि अगर रीडऑनलीक्लेक्शन <टी> नहीं है, तो भी टीस अलग-अलग हैं।
आर्यनांक

4

C # में ऐसी सुविधा नहीं है। आप मान या संदर्भ द्वारा तर्क पास कर सकते हैं। संदर्भ स्वयं अपरिवर्तनीय है जब तक कि आप रेफ संशोधक निर्दिष्ट नहीं करते हैं । लेकिन संदर्भित डेटा अपरिवर्तनीय नहीं है। इसलिए अगर आपको साइड इफेक्ट्स से बचना है तो आपको सावधान रहने की जरूरत है।

MSDN:

पासिंग पैरामीटर्स


अच्छी तरह से मुझे लगता है कि यह सवाल तब तक नीचे आ जाता है: एक कास्ट स्ट्रक्चर न होने के दुष्प्रभावों से बचने का सबसे अच्छा तरीका क्या है?
दसवें सेप

दुर्भाग्य से केवल अपरिवर्तनीय प्रकार ही इसकी मदद कर सकते हैं। आप कल्पना # पर एक नज़र डाल सकते हैं - कुछ दिलचस्प संकलन समय की जाँच कर रहे हैं।
एक्यू

3

इंटरफेस जवाब हैं, और वास्तव में C ++ में "कॉन्स्ट" की तुलना में अधिक शक्तिशाली हैं। const एक समस्या के लिए एक आकार-फिट-सभी समाधान है जहाँ "const" को "सदस्यों को सेट करने या सदस्यों को सेट करने वाली किसी चीज़ को कॉल नहीं करने" के रूप में परिभाषित किया गया है। यह कई परिदृश्यों में कॉन्स्ट-नेस के लिए एक अच्छा आशुलिपि है, लेकिन उन सभी में नहीं। उदाहरण के लिए, एक फ़ंक्शन पर विचार करें जो कुछ सदस्यों के आधार पर एक मूल्य की गणना करता है लेकिन परिणामों को भी कैश करता है। C ++ में, इसे गैर-कास्ट माना जाता है, हालांकि उपयोगकर्ता के दृष्टिकोण से यह अनिवार्य रूप से कास्ट है।

इंटरफेस आपको अपनी कक्षा से प्रदान की जाने वाली क्षमताओं के विशिष्ट सबसेट को परिभाषित करने में अधिक लचीलापन देते हैं। कास्ट-नेस चाहते हैं? बस कोई परिवर्तनशील तरीकों के साथ एक इंटरफ़ेस प्रदान करें। कुछ चीजों को स्थापित करने की अनुमति देना चाहते हैं लेकिन दूसरों को नहीं? बस उन विधियों के साथ एक इंटरफ़ेस प्रदान करें।


15
100% सही नहीं है। C ++ कास्ट विधियों को चिह्नित सदस्यों को म्यूट करने की अनुमति है mutable
कॉन्स्टैंटिन

3
काफी उचित। और कास्ट-कास्टिंग आपको कॉन्स्ट-नेस से छुटकारा दिलाता है। दोनों तरह का मतलब है कि सी ++ डिजाइनरों ने भी एक आकार-फिट का एहसास किया है, यह वास्तव में एक आकार-फिट-सबसे अधिक है।
उदार

8
C ++ का लाभ यह है कि आपके पास अधिकांश मामलों के लिए कॉन्स्टेबल हैं, और आप दूसरों के लिए इंटरफेस लागू कर सकते हैं। अब, const के अलावा, C ++ में परिवर्तनशील कीवर्ड है जो डेटा के कैश या लॉकिंग मैकेनिज्म (म्यूटेक्स या लाइक) के रूप में विशेषताओं पर लागू होता है। कॉन्स्ट 'किसी आंतरिक विशेषता को नहीं बदलेगा) नहीं है, बल्कि वस्तु स्थिति को बाहर से कथित रूप से नहीं बदलेगा। अर्थात्, एक कास्ट विधि को कॉल करने से पहले और बाद में ऑब्जेक्ट का कोई भी उपयोग समान परिणाम देगा।
डेविड रॉड्रिग्ज -

9
C ++ में आने वाली म्यूट करने के लिए कास्ट को दूर करना अपरिभाषित व्यवहार (नाक राक्षसों) है। const_cast विरासत कोड है कि तार्किक रूप से चिह्नित नहीं किया जा रहा है जब कब्ज के साथ इंटरफेस के लिए है।
जे.के.

3

दूसरों में से कुछ के साथ सहमत होने के लिए पठनीय क्षेत्रों का उपयोग करते हुए देखें कि आप अपरिवर्तनीय वस्तुओं को बनाने के लिए, कंस्ट्रक्टर में इनिशियलाइज़ करते हैं।

    public class Customer
    {
    private readonly string m_name;
    private readonly int m_age;

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
    }

    public int Age
    {
        get { return m_age; }
    }
  }

वैकल्पिक रूप से आप संपत्तियों पर एक्सेस स्कोप भी जोड़ सकते हैं, यानी पब्लिक गेट और संरक्षित सेट?

    public class Customer
    {
    private string m_name;
    private int m_age;

    protected Customer() 
    {}

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
        protected set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        protected set { m_age = value; }
    }
  }

3
ये अलग-अलग दृष्टिकोण हैं जो वास्तव में पूरी समस्या के लायक नहीं हैं। अभिगम नियंत्रण स्तर के साथ आप केवल परिवर्तन से कक्षाओं को प्राप्त करने की अनुमति देते हैं, कई मामलों में यह वास्तविक दुनिया को उचित रूप से मॉडल नहीं करेगा। एक शिक्षक छात्र के रिकॉर्ड से नहीं निकलता है, लेकिन छात्र ग्रेड को बदलना चाह सकता है, हालांकि छात्र ग्रेड नहीं बदल सकता है, लेकिन उन्हें पढ़ सकता है ... बस एक साधारण उदाहरण का नाम देने के लिए।
डेविड रॉड्रिग्ज -

2
  • स्थिरांक कीवर्ड ऐसे आदिम प्रकार और तारों के रूप में संकलन समय स्थिरांक के लिए इस्तेमाल किया जा सकता
  • केवल पढ़ने के लिए कीवर्ड ऐसे संदर्भ प्रकार के रूप में चलाने के समय स्थिरांक के लिए इस्तेमाल किया जा सकता

के साथ समस्या केवल पढ़ने के लिए है कि यह केवल संदर्भ (सूचक) स्थिर होने की अनुमति देता है। संदर्भित (इंगित की गई) बात अभी भी संशोधित की जा सकती है। यह मुश्किल हिस्सा है लेकिन इसके आसपास कोई रास्ता नहीं है। निरंतर वस्तुओं को लागू करने का मतलब है कि उन्हें किसी भी परिवर्तनशील तरीकों या गुणों को उजागर न करना लेकिन यह अजीब है।

अपने C # को बेहतर बनाने के लिए प्रभावी C #: 50 विशिष्ट तरीके भी देखें (आइटम 2 - आसानी से कांस्ट को प्राथमिकता दें)।

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