प्रभाव विधि को आसानी से क्षेत्र के लिए कहा जाता है


83

मैं Visual Studio 2010 + Resharper का उपयोग कर रहा हूं और यह निम्नलिखित कोड पर चेतावनी दिखाता है:

if (rect.Contains(point))
{
    ...
}

rectएक readonly Rectangleफ़ील्ड है, और रेस्स्पर मुझे यह चेतावनी दिखाता है:

"इम्प्योर मेथड को वैल्यू टाइप के रेडीली फील्ड के लिए कहा जाता है।"

अशुद्ध तरीके क्या हैं और यह चेतावनी मुझे क्यों दिखाई जा रही है?


जवाबों:


96

सबसे पहले, जॉन, माइकल और जेरेड के उत्तर अनिवार्य रूप से सही हैं लेकिन मेरे पास कुछ और चीजें हैं जिन्हें मैं उनके साथ जोड़ना चाहूंगा।

"अशुद्ध" विधि से क्या अभिप्राय है?

शुद्ध तरीकों को चिह्नित करना आसान है। एक "शुद्ध" विधि में निम्नलिखित विशेषताएं हैं:

  • इसका आउटपुट पूरी तरह से इसके इनपुट से निर्धारित होता है; इसका आउटपुट बाहरी लोगों पर निर्भर नहीं करता है जैसे दिन का समय या आपकी हार्ड डिस्क पर बिट्स। इसका उत्पादन इसके इतिहास पर निर्भर नहीं करता है; किसी दिए गए तर्क के साथ विधि को दो बार कॉल करना एक ही परिणाम देना चाहिए।
  • एक शुद्ध विधि इसके आसपास की दुनिया में कोई अवलोकन योग्य उत्परिवर्तन पैदा नहीं करती है। एक शुद्ध विधि दक्षता के लिए निजी स्थिति को म्यूट करने का विकल्प चुन सकती है, लेकिन एक शुद्ध विधि अपने तर्क के एक क्षेत्र को म्यूट, नहीं कहती है।

उदाहरण के लिए, Math.Cosएक शुद्ध विधि है। इसका आउटपुट केवल इसके इनपुट पर निर्भर करता है, और इनपुट कॉल द्वारा नहीं बदला जाता है।

अशुद्ध विधि एक ऐसी विधि है जो शुद्ध नहीं है।

अशुद्ध तरीकों को आसानी से पारित करने के कुछ खतरे क्या हैं?

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

तो क्या हुआ अगर आप एक चर के बजाय एक मूल्य पर ऐसी विधि कहते हैं? उस स्थिति में हम एक अस्थायी चर बनाते हैं, उसमें मान को कॉपी करते हैं, और चर का संदर्भ देते हैं।

एक पठनीय चर को एक मान माना जाता है, क्योंकि इसे कंस्ट्रक्टर के बाहर म्यूट नहीं किया जा सकता है। इसलिए हम चर को दूसरे चर में कॉपी कर रहे हैं, और अशुद्ध विधि संभवतः प्रतिलिपि को म्यूट कर रही है, जब आप इसे चर को बदलना चाहते हैं।

यह एक रिसीवर के रूप में आसानी से एक संरचना को पारित करने का खतरा है । एक संरचना को पारित करने का एक खतरा भी है जिसमें एक रीडोनिली फ़ील्ड शामिल है। एक संरचना जिसमें एक पठनीय क्षेत्र शामिल है, एक सामान्य अभ्यास है, लेकिन यह अनिवार्य रूप से एक चेक लिख रहा है कि प्रकार प्रणाली में नकदी के लिए धन नहीं है; किसी विशेष चर का "रीड-ओनली-नेस" स्टोरेज के मालिक द्वारा निर्धारित किया जाता है। एक संदर्भ प्रकार का एक उदाहरण "स्वयं का भंडारण" करता है, लेकिन मूल्य प्रकार का एक उदाहरण नहीं होता है!

struct S
{
  private readonly int x;
  public S(int x) { this.x = x; }
  public void Badness(ref S s)
  {
    Console.WriteLine(this.x);   
    s = new S(this.x + 1);
    // This should be the same, right?
    Console.WriteLine(this.x);   
  }
}

एक सोचता है कि this.xपरिवर्तन नहीं होने वाला है क्योंकि x एक पठनीय क्षेत्र है और एक रचनाकार Badnessनहीं है। परंतु...

S s = new S(1);
s.Badness(ref s);

... स्पष्ट रूप से उस के झूठ को दर्शाता है। thisऔर sएक ही चर का संदर्भ लें, और वह चर आसानी से पढ़ा नहीं जाता है!


उचित पर्याप्त है, लेकिन कृपया इस कोड पर विचार करें: ToInt अशुद्ध struct Id { private readonly int _id; public Id(int id) { _id = id; } public int ToInt() => _id; } क्यों है ?
boskicthebrain

@boskicthebrain: क्या आपका प्रश्न वास्तव में है "रेस्परर इसे अपवित्र क्यों मानता है?" यदि यह आपका प्रश्न है, तो किसी ऐसे व्यक्ति को ढूंढें जो R # पर काम करता है और उनसे पूछता है!
एरिक लिपिपर्ट

3
यदि विधि शून्य है और इसके अलावा कुछ नहीं करता है, तो भी Resharper यह चेतावनी देगा return। उसके आधार पर, मैं अनुमान लगा रहा हूं कि एकमात्र मानदंड में यह विशेषता है या नहीं [Pure]
जन्मफ्रेमनेग

मैंने यह कथन पाया "हम हमेशा उस चर के संदर्भ को पास करते हैं जो रिसीवर है" मेरे लिए थोड़ा भ्रमित करने वाला है। पीओ से मामले में, 'चर' का क्या अर्थ है? मुझे लगता है कि यह होगा rect। क्या हम कह रहे हैं कि विधि की एक प्रति rectपारित की गई Containsहै?
xtu

51

एक अशुद्ध विधि वह है जो मूल्य को छोड़ने की गारंटी नहीं है जैसा कि यह था।

.NET 4 में आप विधियों और प्रकारों को सजाने के [Pure]लिए उन्हें शुद्ध घोषित कर सकते हैं, और आर # इस पर ध्यान देंगे। दुर्भाग्य से, आप इसे किसी और के सदस्यों पर लागू नहीं कर सकते हैं, और आप आर # को यह नहीं बता सकते हैं कि एक टाइप / सदस्य एक शुद्ध 3.5 प्रोजेक्ट में शुद्ध है जहां तक ​​मैं जानता हूं। (यह मुझे हर समय नोदा टाइम में काटता है ।)

यह विचार है कि यदि आप एक ऐसी विधि को कॉल कर रहे हैं जो परिवर्तनशील है, लेकिन आप इसे केवल पढ़ने के लिए फ़ील्ड पर कॉल करते हैं, तो यह संभवत: वह नहीं है जो आप चाहते हैं, इसलिए R # आपको इस बारे में चेतावनी देगा। उदाहरण के लिए:

public struct Nasty
{
    public int value;

    public void SetValue()
    {
        value = 10;
    }
}

class Test
{
    static readonly Nasty first;
    static Nasty second;

    static void Main()
    {
        first.SetValue();
        second.SetValue();
        Console.WriteLine(first.value);  // 0
        Console.WriteLine(second.value); // 10
    }
}

यह वास्तव में उपयोगी चेतावनी होगी यदि प्रत्येक विधि जो वास्तव में शुद्ध थी, उस तरह से घोषित की गई थी। दुर्भाग्य से वे नहीं हैं, इसलिए बहुत सारी झूठी सकारात्मकताएं हैं :(


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

@ सहायक: तर्क का मूल्य नहीं - एक अशुद्ध विधि भी ऐसा कर सकती है - लेकिन मूल्य जिसे आप इसे कहते हैं । (मेरा उदाहरण देखें, जहां विधि का भी कोई पैरामीटर नहीं है।)
जॉन स्कीट

2
आप JetBrains.Annotations.PureAttributeइसके बजाय उपयोग कर सकते हैं System.Diagnostics.Contracts.PureAttribute, उनके पास ReSharper कोड विश्लेषण के लिए एक ही अर्थ है और .NET 3.5, .NET 4 या सिल्वरलाइट पर समान रूप से काम करना चाहिए। आप बाह्य रूप से उन असेंबली को भी एनोटेट कर सकते हैं जिनका आप XML फ़ाइलों का उपयोग नहीं करते हैं (ReSharper bin path में ExternalAnnotations निर्देशिका पर एक नज़र डालें), यह वास्तव में काफी उपयोगी हो सकता है!
जूलियन लेबोस्क्वैन

5
@JulienLebosquain: मैं टूल-विशिष्ट एनोटेशन जोड़ना शुरू करने के लिए वास्तव में अनिच्छुक रहूंगा - विशेष रूप से एक ओपन सोर्स प्रोजेक्ट के लिए। एक विकल्प के रूप में जानने के लिए अच्छा है, लेकिन ...
जॉन स्कीट

1
वास्तव में मैंने पाया कि System.Diagnostics.Contracts.PureAttributeआर # 8.2 में इस चेतावनी को दबाया नहीं गया, जबकि JetBrains.Annotations.PureAttributeकिया। दो विशेषताओं के अलग-अलग विवरण भी हैं: अनुबंध की Pureविशेषता का अर्थ है "परिणाम केवल मापदंडों पर निर्भर करता है", जबकि जेटब्रेन का Pureतात्पर्य परिणाम की गणना करने के लिए उपयोग की जा रही वस्तु स्थिति को छोड़कर "दृश्यमान परिवर्तन नहीं करता है"। (लेकिन अभी भी Pureइस चेतावनी पर एक ही प्रभाव नहीं होने के अनुबंध शायद एक बग है।)
वर्म्बो

15

संक्षिप्त उत्तर यह है कि यह एक गलत सकारात्मक है, और आप चेतावनी को अनदेखा कर सकते हैं।

लंबे समय तक उत्तर यह है कि केवल-पढ़ने के लिए एक मान प्रकार की एक प्रतिलिपि बनाता है , ताकि किसी विधि द्वारा किए गए मूल्य में कोई भी परिवर्तन केवल प्रतिलिपि को प्रभावित करे। ReSharper को एहसास नहीं है कि Containsयह एक शुद्ध तरीका है (इसका अर्थ है कि इसका कोई दुष्प्रभाव नहीं है)। एरिक लिपर्ट इसके बारे में यहां बात करते हैं: म्यूटिंग रीडोनली स्ट्रक्चर्स


2
कृपया इस चेतावनी को कभी भी नज़रअंदाज़ न करें जब तक कि पूरी तरह से समझ न आ जाए !!! एक अच्छा उदाहरण जहां यह आपको सुरक्षित कर सकता है यह निर्माण है: private readonly SpinLock _spinLock = new SpinLock();- इस तरह का ताला पूरी तरह से बेकार होगा (क्योंकि हर बार पढ़ने के बाद फ्लाई कॉपी बनाने के लिए प्रतिरूप संशोधन का कारण बनता है। इस पर दर्ज विधि कहा जाता है)
Jan

11

ऐसा लगता है Reshaprer का मानना है कि जैसे कि विधि Containsउत्परिवर्तित कर सकते हैं rectमूल्य। क्योंकि rectएक है readonly structसी # संकलक एक परिवर्तनशील से विधि को रोकने के लिए मूल्य का बचाव की मुद्रा में प्रतियां बनाता है readonlyक्षेत्र। अनिवार्य रूप से अंतिम कोड इस तरह दिखता है

Rectangle temp = rect;
if (temp.Contains(point)) {
  ...
}

रेस्परर आपको यहां चेतावनी दे रहा है कि एक तरह से Containsम्यूट हो सकता है rectजो तुरंत खो जाएगा क्योंकि यह एक अस्थायी पर हुआ था।


इसलिए यह विधि में किए गए किसी भी तर्क को प्रभावित नहीं करेगा, केवल इसे उस मूल्य को उत्परिवर्तित करने से रोकें जो इसे कहा जाता था, है ना?
अम्लीय

5

एक आवेग विधि एक ऐसी विधि है जिसके दुष्प्रभाव हो सकते हैं। इस मामले में, Resharper को लगता है कि यह बदल सकता है rect। यह शायद नहीं है लेकिन सबूतों की श्रृंखला टूट गई है।

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