c# - आप सी#ऑटो-प्रॉपर्टी को डिफ़ॉल्ट मान कैसे देते हैं?




automatic-properties (19)

सी # 5 और इससे पहले, ऑटो कार्यान्वित गुणों को एक डिफ़ॉल्ट मान देने के लिए, आपको इसे एक निर्माता में करना होगा।

ऑटो संपत्ति प्रारंभकर्ताओं की क्षमता सी # 6.0 के बाद शामिल है। वाक्यविन्यास है:

public int X { get; set; } = x; // C# 6 or higher

आप सी # ऑटो-प्रॉपर्टी को डिफ़ॉल्ट मान कैसे देते हैं? मैं या तो कन्स्ट्रक्टर का उपयोग करता हूं, या पुराने वाक्यविन्यास पर वापस आ जाता हूं।

कन्स्ट्रक्टर का उपयोग करना:

class Person 
{
    public Person()
    {
        Name = "Default Name";
    }
    public string Name { get; set; }
}

सामान्य संपत्ति वाक्यविन्यास का उपयोग करना (डिफ़ॉल्ट मान के साथ)

private string name = "Default Name";
public string Name 
{
    get 
    {
        return name;
    }
    set
    {
        name = value;
    }
}

क्या कोई बेहतर तरीका है?


सी # 6 और ऊपर में आप सिंटैक्स का उपयोग कर सकते हैं:

public object Foo { get; set; } = bar;

ध्यान दें कि एक readonly संपत्ति रखने के लिए बस सेट को छोड़ दें, जैसा कि:

public object Foo { get; } = bar;

आप कन्स्ट्रक्टर से readonly ऑटो-गुण भी असाइन कर सकते हैं।

इससे पहले मैंने नीचे जवाब दिया।

मैं निर्माता को डिफ़ॉल्ट जोड़ने से बचना चाहता हूं; गतिशील असाइनमेंट के लिए छोड़ दें और दो बिंदुओं से बचें जिन पर चर निर्दिष्ट किया गया है (यानी प्रकार डिफ़ॉल्ट और कन्स्ट्रक्टर में)। आमतौर पर मैं ऐसे मामलों में एक सामान्य संपत्ति लिखूंगा।

एक अन्य विकल्प यह है कि ASP.Net क्या करता है और किसी विशेषता के माध्यम से डिफ़ॉल्ट को परिभाषित करता है:

http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx


निर्माता में। कन्स्ट्रक्टर का उद्देश्य इसके डेटा सदस्यों को आरंभ करना है।


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



क्या आपने डिफॉल्ट वैल्यूएट्रिब्यूट या कन्फेशियललाइज और कन्स्ट्रक्टर के संयोजन के साथ तरीकों को रीसेट करने का प्रयास किया है? मुझे लगता है कि इन दो तरीकों में से एक आवश्यक है यदि आप ऐसी कक्षा बना रहे हैं जो डिजाइनर सतह पर या संपत्ति ग्रिड में दिखाई दे।


1/2/15 संपादित करें

सी # 6 के साथ आप ऑटो-प्रॉपर्टीज को सीधे शुरू कर सकते हैं (आखिरकार!), अब उस धागे में अन्य उत्तर हैं जो इसका वर्णन करते हैं।

सी # 5 और नीचे के लिए:

हालांकि विशेषता का इच्छित उपयोग वास्तव में गुणों के मान निर्धारित नहीं करना है, फिर भी आप हमेशा उन्हें सेट करने के लिए प्रतिबिंब का उपयोग कर सकते हैं ...

public class DefaultValuesTest
{    
    public DefaultValuesTest()
    {               
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
        {
            DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];

            if (myAttribute != null)
            {
                property.SetValue(this, myAttribute.Value);
            }
        }
    }

    public void DoTest()
    {
        var db = DefaultValueBool;
        var ds = DefaultValueString;
        var di = DefaultValueInt;
    }


    [System.ComponentModel.DefaultValue(true)]
    public bool DefaultValueBool { get; set; }

    [System.ComponentModel.DefaultValue("Good")]
    public string DefaultValueString { get; set; }

    [System.ComponentModel.DefaultValue(27)]
    public int DefaultValueInt { get; set; }
}

सी # 6.0 में यह एक हवा है!

संपत्ति घोषणा घोषणाओं में आप इसे Class घोषणा में ही कर सकते हैं।

public class Coordinate
{ 
    public int X { get; set; } = 34; // get or set auto-property with initializer

    public int Y { get; } = 89;      // read-only auto-property with initializer

    public int Z { get; }            // read-only auto-property with no initializer
                                     // so it has to be initialized from constructor    

    public Coordinate()              // .ctor()
    {
        Z = 42;
    }
}

public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}

जब आप एक चर के लिए प्रारंभिक मान को रेखांकित करते हैं तो यह कन्स्ट्रक्टर में वैसे भी किया जाएगा।

मैं तर्क दूंगा कि यह वाक्यविन्यास सी # से 5 तक का सबसे अच्छा अभ्यास था:

class Person 
{
    public Person()
    {
        //do anything before variable assignment

        //assign initial values
        Name = "Default Name";

        //do anything after variable assignment
    }
    public string Name { get; set; }
}

चूंकि यह आपको ऑर्डर मानों का स्पष्ट नियंत्रण देता है।

सी # 6 के रूप में एक नया तरीका है:

public string Name { get; set; } = "Default Name"

मेरा समाधान एक कस्टम विशेषता का उपयोग करना है जो निरंतर या संपत्ति प्रकार प्रारंभकर्ता का उपयोग करके डिफ़ॉल्ट मान संपत्ति प्रारंभिकता प्रदान करता है।

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InstanceAttribute : Attribute
{
    public bool IsConstructorCall { get; private set; }
    public object[] Values { get; private set; }
    public InstanceAttribute() : this(true) { }
    public InstanceAttribute(object value) : this(false, value) { }
    public InstanceAttribute(bool isConstructorCall, params object[] values)
    {
        IsConstructorCall = isConstructorCall;
        Values = values ?? new object[0];
    }
}

इस विशेषता का उपयोग करने के लिए विशेष बेस क्लास-प्रारंभकर्ता से कक्षा का उत्तराधिकारी होना आवश्यक है या एक स्थिर सहायक विधि का उपयोग करना आवश्यक है:

public abstract class DefaultValueInitializer
{
    protected DefaultValueInitializer()
    {
        InitializeDefaultValues(this);
    }

    public static void InitializeDefaultValues(object obj)
    {
        var props = from prop in obj.GetType().GetProperties()
                    let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false)
                    where attrs.Any()
                    select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) };
        foreach (var pair in props)
        {
            object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0
                            ? pair.Attr.Values[0]
                            : Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values);
            pair.Property.SetValue(obj, value, null);
        }
    }
}

उपयोग उदाहरण:

public class Simple : DefaultValueInitializer
{
    [Instance("StringValue")]
    public string StringValue { get; set; }
    [Instance]
    public List<string> Items { get; set; }
    [Instance(true, 3,4)]
    public Point Point { get; set; }
}

public static void Main(string[] args)
{
    var obj = new Simple
        {
            Items = {"Item1"}
        };
    Console.WriteLine(obj.Items[0]);
    Console.WriteLine(obj.Point);
    Console.WriteLine(obj.StringValue);
}

आउटपुट:

Item1
(X=3,Y=4)
StringValue

सी # (6.0) और अधिक के संस्करण में, आप कर सकते हैं:

रीडोनली गुणों के लिए

public int ReadOnlyProp => 2;

लिखने योग्य और पठनीय गुण दोनों के लिए

public string PropTest { get; set; } = "test";

सी # (7.0) के वर्तमान संस्करण में, आप यह कर सकते हैं: (स्निपेट बल्कि यह दिखाता है कि बैकिंग फ़ील्ड के साथ उपयोग करते समय अभिव्यक्ति प्राप्त करने वाले / सेट एक्सेसर्स का उपयोग करने के लिए आप अधिक कॉम्पैक्ट कैसे बना सकते हैं)

private string label = "Default Value";

// Expression-bodied get / set accessors.
public string Label
{
   get => label;
   set => this.label = value; 
 }

उत्तर के अलावा पहले से ही स्वीकार्य है, परिदृश्य के लिए जब आप किसी अन्य प्रॉपर्टी के फ़ंक्शन के रूप में डिफ़ॉल्ट प्रॉपर्टी को परिभाषित करना चाहते हैं तो आप सी # 6.0 (और उच्चतर) पर अभिव्यक्ति बॉडी नोटेशन का उपयोग कर सकते हैं और यहां तक ​​कि अधिक सुरुचिपूर्ण और संक्षिप्त संरचनाओं के लिए:

public class Person{

    public string FullName  => $"{First} {Last}"; // expression body notation

    public string First { get; set; } = "First";
    public string Last { get; set; } = "Last";
}

आप उपरोक्त निम्नलिखित फैशन में उपयोग कर सकते हैं

    var p = new Person();

    p.FullName; // First Last

    p.First = "Jon";
    p.Last = "Snow";

    p.FullName; // Jon Snow

उपर्युक्त "=>" नोटेशन का उपयोग करने में सक्षम होने के लिए, संपत्ति केवल पढ़ी जानी चाहिए, और आप एक्सेस एक्सेसर कीवर्ड का उपयोग नहीं करते हैं।

MSDN पर विवरण


थोड़ा पूरा नमूना:

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = value; }
}

सी # 6.0 से शुरू , हम स्वत: कार्यान्वित गुणों के लिए डिफ़ॉल्ट मान असाइन कर सकते हैं।

public string Name { get; set; } = "Some Name";

हम केवल पढ़ने योग्य ऑटो लागू संपत्ति भी बना सकते हैं जैसे:

public string Name { get; } = "Some Name";

देखें: सी # 6: पहली प्रतिक्रियाएं, स्वचालित रूप से कार्यान्वित गुणों के लिए प्रारंभकर्ता - जॉन स्कीट द्वारा


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


class Person 
{    
    /// Gets/sets a value indicating whether auto 
    /// save of review layer is enabled or not
    [System.ComponentModel.DefaultValue(true)] 
    public bool AutoSaveReviewLayer { get; set; }
}

कभी-कभी मैं इसका उपयोग करता हूं, अगर मैं नहीं चाहता कि यह वास्तव में सेट हो और मेरे डीबी में बने रहें:

class Person
{
    private string _name; 
    public string Name 
    { 
        get 
        {
            return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
        } 

        set { _name = value; } 
    }
}

जाहिर है अगर यह एक स्ट्रिंग नहीं है तो मैं ऑब्जेक्ट को शून्य (डबल ?, int?) बना सकता हूं और जांच सकता हूं कि यह शून्य है, डिफ़ॉल्ट डिफॉल्ट करें, या उसके द्वारा सेट किए गए मान को वापस कर दें।

फिर मैं अपने भंडार में एक चेक कर सकता हूं यह देखने के लिए कि क्या यह मेरा डिफ़ॉल्ट है और जारी नहीं है, या बचत से पहले बैकिंग वैल्यू की वास्तविक स्थिति देखने के लिए बैकडोर चेक करें।

उम्मीद है की वो मदद करदे!


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





c# automatic-properties