كيف تعطي C#Auto-Property قيمة افتراضية؟




automatic-properties (15)

كيف تعطي C # Auto-Property قيمة افتراضية؟ أنا إما استخدام المنشئ أو العودة إلى بناء الجملة القديم.

باستخدام منشئ:

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;
    }
}

هل هناك طريقة أفضل؟


في C # 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;
    }
}


أعتقد أن هذا من شأنه أن يفعل ذلك ل ya givng SomeFlag افتراضي من false.

private bool _SomeFlagSet = false;
public bool SomeFlag
{
    get
    {
        if (!_SomeFlagSet)
            SomeFlag = false;        

        return SomeFlag;
    }
    set
    {
        if (!_SomeFlagSet)
            _SomeFlagSet = true;

        SomeFlag = value;        
    }
}

استخدم المُنشئ لأنه "عند انتهاء المُنشئ ، يجب إنهاء الإنشاء". الخصائص مثل الحالات التي تحتفظ بها فصولك ، إذا كان عليك تهيئة حالة افتراضية ، فستقوم بذلك في منشئك.


التهيئة في السطر ، باستخدام الصانعين للتهيئة هو ممارسة سيئة وسيؤدي إلى المزيد من التغييرات في وقت لاحق.


الحل الخاص بي هو استخدام سمة مخصصة توفر التهيئة الافتراضية لقيمة القيمة من خلال الثابت أو باستخدام مُهيئ نوع الخاصية.

[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

تحرير 1/2/15

مع C # 6 يمكنك تهيئة الخصائص التلقائية مباشرة (أخيرا!) ، هناك الآن إجابات أخرى في الموضوع الذي يصف ذلك.

ل C # 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; }
}

شخصياً ، لا أرى نقطة جعله ملكية على الإطلاق إذا كنت لن تفعل أي شيء على الإطلاق خارج نطاق السيارات. فقط اتركها كحقل. فائدة التغليف لهذا البند هي مجرد الرنجة الحمراء ، لأنه لا يوجد شيء وراءها للتغليف. إذا احتجت في أي وقت إلى تغيير التنفيذ الأساسي ، فلا تزال لديك حرية إعادة تقييمها كخصائص دون كسر أي شفرة تابعة.

حسنًا ... ربما يكون هذا موضوع سؤال خاص بها لاحقًا


عينة كاملة قليلا:

using System.ComponentModel;

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

في C # 5 والإصدارات السابقة ، لإعطاء الخصائص التي يتم تنفيذها تلقائيًا قيمة افتراضية ، يجب عليك القيام بذلك في مُنشئ.

يتم تضمين القدرة على إضفاء الطابع التلقائي على خاصية السيارات منذ الإصدار 6.0 من C #. الصيغة هي:

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

في الإصدار C # (6.0) وأكبر ، يمكنك القيام بما يلي:

للخصائص Readonly

public int ReadOnlyProp => 2;

لكل من خصائص قابل للكتابة و Readable

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

في الإصدار الحالي من C # (7.0) ، يمكنك القيام بما يلي: (يعرض المقتطف بدلاً من ذلك كيف يمكنك استخدام مكوّنات get / set المتضمنة في التعبير لجعلها أكثر اندماجًا عند استخدام حقول النسخ)

private string label = "Default Value";

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

في المنشئ. الغرض المنشئ هو تهيئة أنه من أعضاء البيانات.




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




automatic-properties