एक फ़ील्ड इनिशियलाइज़र नॉनस्टैटिक फ़ील्ड, विधि, या गुण का संदर्भ नहीं दे सकता है


96

मेरे पास एक वर्ग है और जब मैं इसे किसी अन्य कक्षा में उपयोग करने का प्रयास करता हूं तो मुझे नीचे त्रुटि प्राप्त होती है।

using System;
using System.Collections.Generic;
using System.Linq;

namespace MySite
{
    public class Reminders
    {
        public Dictionary<TimeSpan, string> TimeSpanText { get; set; }

        // We are setting the default values using the Costructor
        public Reminders()
        {
            TimeSpanText.Add(TimeSpan.Zero, "None");
            TimeSpanText.Add(new TimeSpan(0, 0, 5, 0), "5 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 15, 0), "15 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 30, 0), "30 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 1, 0, 0), "1 hour before");
            TimeSpanText.Add(new TimeSpan(0, 2, 0, 0), "2 hours before");
            TimeSpanText.Add(new TimeSpan(1, 0, 0, 0), "1 day before");
            TimeSpanText.Add(new TimeSpan(2, 0, 0, 0), "2 day before");
        }

    }
}

दूसरे वर्ग में कक्षा का उपयोग करना

class SomeOtherClass
{  
    private Reminders reminder = new Reminders();
    // error happens on this line:
    private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
    ....

त्रुटि (CS0236):

A field initializer cannot reference the nonstatic field, method, or property

ऐसा क्यों होता है और इसे कैसे ठीक किया जाए?

जवाबों:


147

यह रेखा:

private dynamic defaultReminder = 
                          reminder.TimeSpanText[TimeSpan.FromMinutes(15)];

आप किसी अन्य आवृत्ति चर को प्रारंभ करने के लिए किसी आवृत्ति चर का उपयोग नहीं कर सकते । क्यों? क्योंकि कंपाइलर इन्हें पुनर्व्यवस्थित कर सकता है - इस बात की कोई गारंटी नहीं है कि reminderपहले इनिशियलाइज़ किया जाएगा defaultReminder, इसलिए उपरोक्त लाइन ए को फेंक सकती है NullReferenceException

इसके बजाय, बस उपयोग करें:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

वैकल्पिक रूप से, निर्माता में मान सेट करें:

private dynamic defaultReminder;

public Reminders()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
}

MSDN पर इस संकलक त्रुटि के बारे में अधिक विवरण हैं - संकलक त्रुटि CS0236


3
इस तरह के निर्माणों के लिए जावा अधिक 'क्षमाशील' है। पता नहीं कि यह अच्छी बात है। stackoverflow.com/questions/1494735/…
राउटर स्कूट

32
नहीं, कंपाइलर इनिशियलाइज़र को पुनर्व्यवस्थित नहीं कर सकता है। C # भाषा विनिर्देश बताता है, "10.5.5.2 इंस्टेंस फील्ड इनिशियलाइज़ेशन" सेक्शन के तहत, निम्नलिखित: वैरिएबल इनिशियलाइज़र्स को पाठ क्रम में निष्पादित किया जाता है जिसमें वे कक्षा घोषणा में दिखाई देते हैं। इसे "10.11.2 इंस्टेंस वैरिएबल इनिशियलाइजर्स" में भी दोहराया जाता है, जहां वे कहते हैं: वैरिएबल इनिशियलाइजर्स को टेक्स्ट क्रम में निष्पादित किया जाता है जिसमें वे क्लास डिक्लेरेशन में दिखाई देते हैं। तो आपकी व्याख्या गलत है। आदेश तय हो गया है। इसका कारण यह है कि यह अस्वीकृत है कि C # के डिजाइनर इस तरह से चाहते थे।
जेपी स्टिग नीलसन

(केवल partial classकई फ़ाइलों में "भागों" के साथ मामले में , फ़ील्ड इनिशियलाइज़र का आदेश अस्पष्ट है, लेकिन यह staticखेतों में भी जाता है !)
जेपी स्टिग नील्सन

@WouterSchut आपके द्वारा लिंक किया गया धागा Java के बारे में नहीं है ?! यह C # के रूप में अच्छी तरह से है, लेकिन staticउदाहरण के क्षेत्रों के बजाय फ़ील्ड के साथ ।
जेपी स्टिग नील्सन

2
@ और बिल्कुल भी सच नहीं है, कई फैसले बुरी प्रथाओं को रोकने के लिए किए जाते हैं। भले ही वे, सैद्धांतिक रूप से, लागू हो सकते हैं, कुछ चेतावनियों द्वारा संरक्षित हैं, और कुछ सादे त्रुटियां हैं। और मुझे लगता है कि यह इन मामलों में से एक है ... भले ही मानक कहता है कि यह अनुक्रमिक है, यहां तक ​​कि एक अनुभवी डेवलपर इसे आत्मविश्वास के साथ नहीं कहेगा (मानक की खोज के बिना)।
तोमर डब्ल्यू

22

आपको उस कोड को अपनी क्लास के कंस्ट्रक्टर में डालना होगा:

private Reminders reminder = new Reminders();
private dynamic defaultReminder;

public YourClass()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

इसका कारण यह है कि आप एक क्षेत्र चर का उपयोग करके दूसरे को प्रारंभ करने के लिए एक आवृत्ति चर का उपयोग नहीं कर सकते हैं।


10

आप इस तरह का उपयोग कर सकते हैं

private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 

11
ढेर अतिप्रवाह में आपका स्वागत है! हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और वे लोग आपके कोड सुझाव के कारणों को नहीं जान सकते हैं। कृपया अपने कोड को व्याख्यात्मक टिप्पणियों के साथ भीड़ देने की कोशिश न करें, क्योंकि इससे कोड और स्पष्टीकरण दोनों की पठनीयता कम हो जाती है!
जम्मेटीस

3
यह = के बजाय = का उपयोग कर रहा है।
विंसेंट

3
इस तकनीक का उपयोग करने में सावधानी बरतें, क्योंकि उपयोग =>करने से वास्तविक मूल्य निर्धारित नहीं होता है, लेकिन हर बार defaultReminderएक्सेस होने पर कोड निष्पादित होगा । इसका इरादा नहीं हो सकता है, और नकारात्मक प्रदर्शन प्रभाव हो सकता है, या जीसी आदि के लिए अवांछित दबाव उत्पन्न कर सकता है
स्मेलिवर

4

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];एक फ़ील्ड इनिशलाइज़र है और पहले निष्पादित होता है (किसी भी फ़ील्ड के बिना इनिशलाइज़र अपने डिफ़ॉल्ट मान पर सेट किया जाता है और इनवॉइस उदाहरण से पहले कंस्ट्रक्टर निष्पादित होता है)। ऐसे इंस्टेंस फ़ील्ड जिनके पास कोई इनिशियलाइज़र नहीं है, सभी इंस्टेंस फ़ील्ड इनिशियलाइज़र के पूरा होने के बाद केवल एक कानूनी (डिफ़ॉल्ट) मान होगा। इनिशियलाइज़ेशन ऑर्डर के कारण, इंस्टा कंस्ट्रक्टर्स को अंतिम रूप से निष्पादित किया जाता है, यही वजह है कि इंस्टेंस अभी तक नहीं बनाया गया है क्योंकि इनिशियलाइज़र निष्पादित होते हैं। इसलिए कंपाइलर किसी भी इंस्टेंस प्रॉपर्टी (या फील्ड) को क्लास इंस्टेंस के पूरी तरह से बनने से पहले रेफर नहीं कर सकता। ऐसा इसलिए है क्योंकि reminderसंकलित चर जैसे किसी भी पहुँच का उदाहरण संकलित करने के लिए उदाहरण ( this) संकलक का उपयोग करने के लिए उदाहरण के ठोस स्मृति स्थान को बताने के लिए है।

यह भी कारण है कि thisएक उदाहरण क्षेत्र आरंभीकरण में अनुमति नहीं है।

एक आवृत्ति क्षेत्र के लिए एक वैरिएबल इनिशियलाइज़र बनाए जा रहे उदाहरण को संदर्भित नहीं कर सकता। इस प्रकार, यह एक चर आरंभीकरण में संकलित करने के लिए एक संकलन-समय की त्रुटि है, क्योंकि यह एक चर प्रथमाक्षर के लिए एक सरल-नाम के माध्यम से किसी भी उदाहरण के सदस्य को संदर्भित करने के लिए एक संकलन-समय की त्रुटि है ।

केवल प्रकार सदस्यों प्रारंभ जाने की गारंटी है कि इससे पहले कि उदाहरण के क्षेत्र initializers क्रियान्वित कर रहे हैं वर्ग (स्थिर) क्षेत्र initializers और वर्ग (स्थिर) निर्माणकर्ता और वर्ग तरीके हैं। चूंकि स्थिर सदस्य स्वतंत्र हैं, उन्हें किसी भी समय संदर्भित किया जा सकता है:

class SomeOtherClass
{
  private static Reminders reminder = new Reminders();

  // This operation is allowed,
  // since the compiler can guarantee that the referenced class member is already initialized
  // when this instance field initializer executes
  private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

यही कारण है कि उदाहरण के क्षेत्र के शुरुआती को केवल एक वर्ग सदस्य (स्थिर सदस्य) को संदर्भित करने की अनुमति है। यह संकलक आरंभीकरण नियम एक नियतात्मक प्रकार की तात्कालिकता सुनिश्चित करेगा।

अधिक जानकारी के लिए मैं इस दस्तावेज़ की अनुशंसा करता हूं: Microsoft डॉक्स: कक्षा घोषणाएं

इसका अर्थ है कि एक इंस्टेंस फ़ील्ड जो किसी अन्य इंस्टेंस सदस्य को उसके मान को इनिशियलाइज़ करने के लिए संदर्भित करता है, उसे इंस्टेंस कंस्ट्रक्टर से इनिशियलाइज़ किया जाना चाहिए या संदर्भित सदस्य को घोषित किया जाना चाहिए static

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