C # 3.0+ में संपत्ति और फ़ील्ड के बीच अंतर


140

मुझे पता है कि यह लगता है कि एक डुप्लिकेट और सी # में एक संपत्ति के बीच अंतर क्या है? लेकिन मेरे प्रश्न में थोड़ा अंतर है (मेरे दृष्टिकोण से):

एक बार मुझे पता है कि

  • मैं अपनी कक्षा का उपयोग "तकनीकों पर नहीं करता जो केवल गुणों पर काम करती है" और
  • मैं गेटटर / सेटर में सत्यापन कोड का उपयोग नहीं करूंगा।

क्या संपत्ति स्थापित करने में किसी प्रकार के नियंत्रण की तरह कोई अंतर (शैली / भविष्य के विकास को छोड़कर) है?

क्या इसके बीच कोई अतिरिक्त अंतर है:

public string MyString { get; set; }

तथा

public string myString;

(मुझे पता है कि, पहले संस्करण के लिए C # 3.0 या इसके बाद के संस्करण की आवश्यकता है और संकलक निजी फ़ील्ड बनाता है।)


जवाबों:


117

Encapsulation।

दूसरे उदाहरण में आपने केवल एक चर को परिभाषित किया है, पहले में, चर के चारों ओर एक गेटर / सेटर है। इसलिए यदि आप तय करते हैं कि आप बाद की तारीख में चर को मान्य करना चाहते हैं - तो यह बहुत आसान होगा।

इसके अलावा वे Intellisense में अलग तरह से दिखाने :)

संपादित करें: ओपी अपडेट किए गए प्रश्न के लिए अपडेट - यदि आप यहां अन्य सुझावों को अनदेखा करना चाहते हैं, तो दूसरा कारण यह है कि यह केवल अच्छा ओओ डिजाइन नहीं है। और अगर आपके पास इसे करने का बहुत अच्छा कारण नहीं है, तो हमेशा एक सार्वजनिक चर / क्षेत्र पर एक संपत्ति चुनें।


9
यह आसान क्यों होगा? मुझे एक फ़ील्ड को संपत्ति में बदलने और निजी बैकिंग फ़ील्ड जोड़ने से क्या रोकता है? यह कॉलिंग कोड को कैसे प्रभावित करता है?
सर्ज वुटिएर

30
@ सर्ज - यह पहले से संकलित कोड को प्रभावित करता है। उदाहरण के लिए, यदि आप एक ऐसी लाइब्रेरी विकसित कर रहे हैं, जिसका उपयोग कई अनुप्रयोगों द्वारा किया जाता है, तो उस लाइब्रेरी में एक प्रॉपर्टी में फ़ील्ड को बदलते हुए प्रत्येक एप्लिकेशन के एक recompile की आवश्यकता होगी। यदि यह एक संपत्ति थी, तो आप बिना किसी चिंता के संपत्ति को अपडेट कर सकते हैं।
डस्टिन कैंपबेल

मैं आपसे पूरी तरह सहमत हूं, मैं हमेशा गुणों का उपयोग करता हूं। मैं बस एक संभावित अंतर को लेकर उत्सुक था
p4bl0

24
यदि उपभोग करने वाले कोड को हमेशा प्रभावित वर्ग के रूप में एक ही समय में
बदला

1
वाह Shuggy आपकी टिप्पणी बिल्कुल जवाब मैं देख रहा था!
p4bl0

160

फ़ील्ड और गुण समान दिखते हैं, लेकिन वे नहीं हैं। गुण विधियां हैं और जैसे कि कुछ चीजें हैं जो गुणों के लिए समर्थित नहीं हैं, और कुछ चीजें जो गुणों के साथ हो सकती हैं लेकिन खेतों के मामले में कभी नहीं।

यहां अंतरों की एक सूची दी गई है:

  • फ़ील्ड का उपयोग out/refतर्कों के इनपुट के रूप में किया जा सकता है। गुण नहीं कर सकते।
  • एक फ़ील्ड हमेशा एक ही परिणाम देगा जब कई बार कहा जाता है (यदि हम कई थ्रेड्स के साथ समस्याओं को छोड़ देते हैं)। एक संपत्ति जैसे कि DateTime.Nowहमेशा खुद के बराबर नहीं होती है।
  • गुण अपवादों को फेंक सकते हैं - क्षेत्र कभी ऐसा नहीं करेंगे।
  • गुणों के दुष्प्रभाव हो सकते हैं या निष्पादित करने के लिए वास्तव में लंबा समय लग सकता है। फ़ील्ड्स का कोई साइड इफेक्ट नहीं है और हमेशा उतनी ही तेजी से होगा जितना कि दिए गए प्रकार के लिए उम्मीद की जा सकती है।
  • गुण गेटर्स / सेटर के लिए अलग-अलग एक्सेसिबिलिटी का समर्थन करते हैं - फ़ील्ड नहीं (लेकिन फ़ील्ड बनाए जा सकते हैं readonly)
  • प्रतिबिंब का उपयोग करते समय गुणों और क्षेत्रों को अलग-अलग माना जाता है MemberTypesताकि वे अलग-अलग स्थित हों ( उदाहरण के लिए GetFieldsबनाम GetProperties)
  • जेआईटी कंपाइलर फील्ड एक्सेस की तुलना में प्रॉपर्टी एक्सेस को बहुत अलग तरह से ट्रीट कर सकता है। हालाँकि यह समान मूल कोड के लिए संकलित हो सकता है लेकिन अंतर की गुंजाइश है।

11
ध्यान दें कि इनमें से कई बिंदुओं में अंतर नहीं होना चाहिए यदि अच्छी प्रथाओं को नियोजित किया जाता है। यही है, गुणों को वास्तव में साइड इफेक्ट नहीं होना चाहिए, और न ही उन्हें निष्पादित करने में लंबा समय लेना चाहिए।
नोल्डोरिन

15
@ नोल्डोरिन: मैं सहमत हूं, लेकिन दुर्भाग्य से यहां कीवर्ड होना चाहिए । उन क्षेत्रों के साथ जो व्यवहार की गारंटी है। मैं यह नहीं कह रहा हूं कि आपको खेतों का उपयोग करना चाहिए, लेकिन सिमेंटिक अंतर के बारे में पता होना महत्वपूर्ण है।
ब्रायन रासमुसेन

4
हाँ, काफी उचित है। शुरुआत के प्रोग्रामर के पास अक्सर इन बातों के बारे में कोई सुराग नहीं होता है, दुर्भाग्य से ...
Noldorin

2
इसके अलावा, खेतों में एक क्षेत्र इनिशियलाइज़र हो सकता है जबकि गुणों को एक कंस्ट्रक्टर में आरंभीकृत किया जाना है।
Dio F

3
मुझे लगता है कि यह उत्तर स्वीकृत उत्तर की तुलना में बेहतर है। मैं यह सोचना शुरू कर रहा हूं कि खेतों पर गुणों को प्राथमिकता देने का "स्वीकार्य" तरीका खराब सोच है। यदि आपको केवल डेटा से निपटने की आवश्यकता है, तो एक फ़ील्ड का उपयोग करें। यदि आपको डेटा के लिए कार्यक्षमता लागू करने की आवश्यकता है, तो एक विधि का उपयोग करें। चूंकि गुणों के साइड-इफेक्ट्स हो सकते हैं, आप जागरूक नहीं हैं (विशेषकर यदि आपने लाइब्रेरी को डिज़ाइन नहीं किया है और बहुत कम दस्तावेज़ीकरण हैं), तो वे ज्यादातर मामलों में मेरे लिए सहज लगते हैं।
डेविड पेटर्सन

41

एक युगल त्वरित, स्पष्ट अंतर

  1. एक संपत्ति में एक्सेसर कीवर्ड हो सकते हैं।

    public string MyString { get; private set; }
  2. वंशजों में एक संपत्ति को ओवरराइड किया जा सकता है।

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2 दिलचस्प है .. मैंने इसके बारे में नहीं सोचा था
p4bl0

14

मूलभूत अंतर यह है कि एक फ़ील्ड मेमोरी में एक स्थिति है जहां निर्दिष्ट प्रकार का डेटा संग्रहीत किया जाता है। एक संपत्ति कोड की एक या दो इकाइयों का प्रतिनिधित्व करती है जो निर्दिष्ट प्रकार के मूल्य को पुनः प्राप्त या सेट करने के लिए निष्पादित की जाती हैं। इन एक्सेसर विधियों का उपयोग एक क्षेत्र के समान व्यवहार करने वाले सदस्य का उपयोग करके वाक्यविन्यास को छिपाया जाता है (इसमें वह असाइनमेंट ऑपरेशन के दोनों ओर दिखाई दे सकता है)।


11

खेतों की तुलना में एक्सेसर्स अधिक हैं। दूसरों ने पहले ही कई महत्वपूर्ण अंतर बताए हैं, और मैं एक और जोड़ने जा रहा हूं।

गुण इंटरफ़ेस कक्षाओं में भाग लेते हैं। उदाहरण के लिए:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

इस इंटरफ़ेस को कई तरीकों से संतुष्ट किया जा सकता है। उदाहरण के लिए:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

इस कार्यान्वयन में हम दोनों Personवर्ग को एक अमान्य स्थिति में लाने से बचा रहे हैं, साथ ही फोन करने वाले को अप्रकाशित संपत्ति से बाहर निकलने से रोक रहे हैं।

लेकिन हम डिजाइन को और भी आगे बढ़ा सकते हैं। उदाहरण के लिए, इंटरफ़ेस सेटर के साथ व्यवहार नहीं कर सकता है। यह कहना काफी वैध है कि IPersonइंटरफ़ेस के उपभोक्ता केवल संपत्ति प्राप्त करने में रुचि रखते हैं, इसे स्थापित करने में नहीं:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Personवर्ग का पिछला कार्यान्वयन इस इंटरफ़ेस को संतुष्ट करता है। तथ्य यह है कि यह फोन करने वाले को भी सेट करने देता है गुण उपभोक्ताओं (जो उपभोग करते हैं IPerson) के दृष्टिकोण से व्यर्थ है । कंक्रीट कार्यान्वयन की अतिरिक्त कार्यक्षमता को ध्यान में रखा जाता है, उदाहरण के लिए, बिल्डर:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

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

एक पूरी तरह से मान्य कार्यान्वयन IPersonएक अपरिवर्तनीय व्यक्ति वर्ग और एक संबंधित व्यक्ति कारखाना होगा:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

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


7

पहले वाला:

public string MyString {get; set; }

एक संपत्ति है; दूसरा एक ( public string MyString) एक क्षेत्र को दर्शाता है।

अंतर यह है, कि कुछ निश्चित तकनीकें (उदाहरणों के लिए ASP.NET डेटाबाइंडिंग), केवल गुणों पर काम करती हैं, न कि खेतों पर। XML Serialization के लिए भी यही सच है: केवल गुण क्रमबद्ध हैं, फ़ील्ड क्रमबद्ध नहीं हैं।


8
गलत। XML सीरियलाइज़ेशन सार्वजनिक क्षेत्रों को क्रमबद्ध करता है।
सर्ज वुटिएर

2
शायद। लेकिन जब आप किसी क्लास से ऑब्जेक्ट डेटा सोर्स बनाते हैं, तो आपको केवल प्रॉपर्टीज़ का उपयोग करना होता है, न कि फ़ील्ड्स का। (जब तक मैंने कुछ गलत नहीं किया है: पी)
स्विश

अच्छा है DRY;) लेकिन मैं एक बार फिर लिखता हूं, मुझे C # भाषा में संपत्ति की मजबूत भूमिका पसंद है। जावा की तुलना में बहुत बेहतर लागू किया गया है (परिणामस्वरूप शुरुआत से) कई, शायद सभी .net समाधान केवल गुणों पर काम करते हैं। WPF, ASPX और अधिक।
Jacek Cz

3

कई मामलों में, गुण और क्षेत्र समान हो सकते हैं, लेकिन वे नहीं हैं। ऐसे गुणों की सीमाएँ हैं जो फ़ील्ड के लिए मौजूद नहीं हैं, और इसके विपरीत।

जैसा कि दूसरों ने उल्लेख किया है। आप प्रॉपर्टी को केवल निजी या राइट-ओनली बना सकते हैं। आप एक क्षेत्र के साथ ऐसा नहीं कर सकते। गुण आभासी भी हो सकते हैं, जबकि फ़ील्ड नहीं हो सकते।

गेटएक्सएक्सएक्सएक्स () / सेटएक्सएक्सएक्सएक्स () फ़ंक्शन के लिए सिंटैक्टिक चीनी के रूप में गुणों के बारे में सोचें। यह कैसे वे पर्दे के पीछे लागू किया जाता है।


1

खेतों और गुणों के बीच एक और महत्वपूर्ण अंतर है।

WPF का उपयोग करते समय, आप केवल सार्वजनिक संपत्तियों से जुड़ सकते हैं। सार्वजनिक क्षेत्र में बांधने से काम नहीं चलेगा । यह तब भी सच है जब लागू नहीं INotifyPropertyChanged(भले ही आपको हमेशा करना चाहिए)।


अच्छा है DRY;) लेकिन मैं एक बार फिर लिखता हूं, मुझे C # भाषा में संपत्ति की मजबूत भूमिका पसंद है। जावा की तुलना में बहुत बेहतर लागू किया गया है (परिणामस्वरूप शुरुआत से) कई, शायद सभी .net समाधान केवल गुणों पर काम करते हैं। WPF, ASPX और अधिक।
Jacek Cz

1

अन्य उत्तरों और उदाहरणों के बीच, मुझे लगता है कि यह उदाहरण कुछ स्थितियों में उपयोगी है।

उदाहरण के लिए मान लें कि आपके पास निम्न प्रकार है:OnChange property

public Action OnChange { get; set; }

आप उपयोग प्रतिनिधियों चाहते हैं तो आप इसे बदलने की जरूरत की तुलना में OnChangeकरने के लिए fieldइस तरह:

public event Action OnChange = delegate {};

ऐसी स्थिति में हम अपने क्षेत्र को अवांछित पहुंच या संशोधन से बचाते हैं।


0

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


"हमेशा" कठिन शब्द के लिए एक तर्क है। सी # में (जावा से बेहतर) संपत्ति में मजबूत स्थिति है, एएसपी, डब्ल्यूपीएफ और अन्य में "बाइंडिंग" का मुख्य (बिना अपवाद) तरीका है। लेकिन फिर भी मैं कल्पना कर सकता हूँ कि क्षेत्र में कोई संपत्ति नहीं है (कभी-कभी)
Jacek Cz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.