मैं कैसे अपरिवर्तनीय क्षेत्रों पर बसता हूं?


25

मेरे पास दो readonly intक्षेत्रों के साथ एक वर्ग है । वे गुणों के रूप में उजागर होते हैं:

public class Thing
{
    private readonly int _foo, _bar;

    /// <summary> I AM IMMUTABLE. </summary>
    public Thing(int foo, int bar)
    {
        _foo = foo;
        _bar = bar;
    }

    public int Foo { get { return _foo; } set { } }

    public int Bar { get { return _bar; } set { } }
}

हालांकि, इसका मतलब है कि निम्नलिखित पूरी तरह से कानूनी कोड है:

Thing iThoughtThisWasMutable = new Thing(1, 42);

iThoughtThisWasMutable.Foo = 99;  // <-- Poor, mistaken developer.
                                  //     He surely has bugs now. :-(

काम करने वाले कीड़े यह मानते हैं कि काम करना निश्चित है। ज़रूर, गलत डेवलपर को डॉक्स पढ़ना चाहिए। लेकिन यह इस तथ्य को नहीं बदलता है कि कोई संकलन- या रन-टाइम त्रुटि ने उसे समस्या के बारे में चेतावनी नहीं दी।

Thingवर्ग को कैसे बदला जाना चाहिए ताकि देवता उपरोक्त गलती करने की संभावना कम हो?

एक अपवाद फेंको? प्रॉपर्टी के बजाय गटर विधि का उपयोग करें?



1
धन्यवाद, @gnat वह पोस्ट (प्रश्न और उत्तर दोनों) इंटरफेस के बारे में बात कर रहा है, जैसा कि कैपिटल I में है Interfaces। मुझे यकीन नहीं है कि मैं क्या कर रहा हूँ।
kdbanman

6
@ नागट, वह भयानक सलाह है। इंटरफेस सार्वजनिक रूप से अपरिवर्तनीय वीओ / डीटीओ की सेवा का एक शानदार तरीका प्रदान करते हैं जो अभी भी परीक्षण करना आसान है।
डेविड अरनो

4
@gnat, मैंने किया और सवाल का कोई मतलब नहीं है क्योंकि ओपी को लगता है कि इंटरफेस अस्थिरता को नष्ट कर देंगे, जो बकवास है।
डेविड अरनो

1
@gnat, यह सवाल डीटीओ के लिए इंटरफेस घोषित करने के बारे में था। शीर्ष मतदान का जवाब था कि इंटरफेस हानिकारक नहीं होगा, लेकिन शायद अनावश्यक।
पॉल ड्रेपर

जवाबों:


107

उस कोड को कानूनी क्यों बनाया जाए? अगर यह कुछ नहीं करता है तो
बाहर set { }निकालें।
यह है कि आप केवल एक सार्वजनिक संपत्ति को कैसे परिभाषित करते हैं:

public int Foo { get { return _foo; } }

3
मुझे नहीं लगा कि यह किसी कारण से कानूनी था, लेकिन यह पूरी तरह से काम करता है! पूर्ण धन्यवाद।
kdbanman

1
@kdbanman यह शायद कुछ के साथ कुछ करना है जिसे आपने आईडीई को एक बिंदु पर करते देखा है - शायद ऑटो-पूरा।
Panzercrisis

2
@kdbanman; क्या कानूनी नहीं है (C # 5 तक) public int Foo { get; }(ऑटो प्रापर्टी विथ अ ग्रेटर) लेकिन public int Foo { get; private set; }है।
लॉरेंट एलए रिज़ज़ा

@LaurentLARIZZA, आपने मेरी मेमोरी को जॉग किया है। बस यहीं से मेरा भ्रम हो गया।
kdbanman

45

C # 5 के साथ और पहले, हम एक गेटर के माध्यम से अपरिवर्तनीय क्षेत्रों के लिए दो विकल्पों का सामना कर रहे थे:

  1. केवल पढ़ने योग्य बैकिंग वैरिएबल बनाएं और मैन्युअल गेटर के माध्यम से वापस लौटें। यह विकल्प सुरक्षित है ( readonlyअपरिवर्तनीयता को नष्ट करने के लिए किसी को स्पष्ट रूप से हटा देना चाहिए । इसने हालांकि बहुत सारे बॉयलर-प्लेट कोड बनाए हैं।
  2. निजी सेटर के साथ, ऑटो-संपत्ति का उपयोग करें। यह सरल कोड बनाता है, लेकिन गलती से अपरिवर्तनीयता को तोड़ना आसान है।

C # 6 के साथ यद्यपि (VS2015 में उपलब्ध है, जिसे कल जारी किया गया था), अब हमें दोनों दुनिया के सर्वश्रेष्ठ मिलते हैं: केवल-पढ़ने के लिए ऑटो गुण। यह हमें ओपी की कक्षा को सरल बनाने की अनुमति देता है:

public class Thing
{
    /// <summary> I AM IMMUTABLE. </summary>
    public Thing(int foo, int bar)
    {
        Foo = foo;
        Bar = bar;
    }

    public int Foo { get; }
    public int Bar { get; }
}

Foo = fooऔर Bar = barलाइनों निर्माता (जो मजबूत केवल पढ़ने के लिए आवश्यकता को प्राप्त होता है) और समर्थन क्षेत्र में ही मान्य निहित है, बल्कि स्पष्ट रूप से परिभाषित किया जाना है (जो सरल कोड को प्राप्त होता है) की तुलना में कर रहे हैं।


2
और प्राथमिक निर्माणकर्ता आगे भी इसे सरल कर सकते हैं, निर्माणकर्ता के सिंटैक्टिक ओवरहेड से छुटकारा पाकर।
सेबेस्टियन रेडल


1
@ डैनलियन्स डेमन, मैं अपने पूरे कोडबेस में इसका इस्तेमाल करना चाह रहा था।
सेबेस्टियन रेडल

12

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

public class Thing
{
    public Thing(int foo, int bar)
    {
        Foo = foo;
        Bar = bar;
    }

    public int Foo { get; private set; }

    public int Bar { get; private set; }
}

1
" public int Foo { get; private set; }" वह वर्ग अब अपरिवर्तनीय नहीं है क्योंकि वह स्वयं को बदल सकता है। हालांकि धन्यवाद!
kdbanman

4
वर्णित वर्ग अपरिवर्तनीय है, क्योंकि यह स्वयं को बदलता नहीं है।
डेविड अर्नो

1
मेरा वास्तविक वर्ग थोड़ा और अधिक जटिल है जो मैंने MWE को दिया था। मैं वास्तविक अपरिवर्तनीयता के बाद हूं , थ्रेड सुरक्षा और क्लास-आंतरिक गारंटी के साथ पूरा।
kdbanman

4
@kdbanman, और आपकी बात क्या है? यदि आपकी कक्षा केवल निर्माण के दौरान निजी बसने वालों को लिखती है, तो उसने "वास्तविक अपरिवर्तनीयता" को लागू किया है। readonlyकीवर्ड सिर्फ एक poka-योक है यानि यह वर्ग भविष्य में immutablity तोड़ने के खिलाफ की रक्षा करता है; हालांकि यह अपरिवर्तनीयता प्राप्त करने के लिए आवश्यक नहीं है।
डेविड अर्नो

3
दिलचस्प शब्द, मुझे इसे गूगल करना था - पोका-योक एक जापानी शब्द है जिसका अर्थ है "गलती-प्रूफिंग"। आप सही हे! ठीक यही मैं कर रहा हूं।
kdbanman

6

दो समाधान।

सरल:

डेविड द्वारा अपरिवर्तनीय पठनीय वस्तुओं के रूप में बसाया जाना शामिल नहीं है।

वैकल्पिक रूप से:

बसने वालों को एक नई अपरिवर्तनीय वस्तु को वापस करने की अनुमति दें, पूर्व की तुलना में क्रिया करें लेकिन प्रत्येक प्रारंभिक वस्तु के लिए समय के साथ राज्य प्रदान करता है। यह डिज़ाइन थ्रेड सुरक्षा और अपरिवर्तनीयता के लिए एक बहुत ही उपयोगी उपकरण है जो सभी अनिवार्य OOP भाषाओं पर फैला हुआ है।

स्यूडोकोड

public class Thing
{

{readonly vars}

    public Thing(int foo, int bar)
    {
        _foo = foo;
        _bar = bar;
    }

    public Thing withFoo(int foo) {
        return new Thing(foo, getBar());
    }

    public Thing withBar(int bar) {
        return new Thing(getFoo(), bar)
    }

    etc...
}

सार्वजनिक स्थैतिक कारखाना

public class Thing
{

{readonly vars}

    private Thing(int foo, int bar)
    {
        _foo = foo;
        _bar = bar;
    }

    public static with(int foo, int bar) {
        return new Thing(foo, bar)
    }

    public Thing withFoo(int foo) {
        return new Thing(foo, getBar());
    }

    public Thing withBar(int bar) {
        return new Thing(getFoo(), bar)
    }

    etc...
}

2
setXYZ कारखाने के तरीकों के लिए भयानक नाम हैं, withXYZ या पसंद पर विचार करें।
बेन वोइगट जूल

धन्यवाद, आपकी उपयोगी टिप्पणी को प्रतिबिंबित करने के लिए मेरे उत्तर को अपडेट किया। :-)
मैट स्मिथस जूल

यह प्रश्न विशेष रूप से संपत्ति बसने वालों के बारे में पूछ रहा था , न कि सेटर विधियों के बारे में।
user253751

सच है, लेकिन ओपी एक संभावित भविष्य के डेवलपर से उत्परिवर्तित राज्य के बारे में चिंतित है। निजी आसानी से या निजी अंतिम कीवर्ड का उपयोग करने वाले चर स्व-दस्तावेजीकरण होने चाहिए, जो कि मूल देव दोष नहीं है यदि यह समझ में नहीं आता है। राज्य को बदलने के विभिन्न तरीकों को समझना महत्वपूर्ण है। मैंने एक और दृष्टिकोण जोड़ा है जो बहुत मददगार है। कोड की दुनिया में बहुत सारी चीजें हैं जो अत्यधिक व्यामोह का कारण बनती हैं, निजी आसानी से होने वाले संस्करण उनमें से एक नहीं होना चाहिए।
मैट स्मिथस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.