الفرق بين الخاصية والحقل في C#3.0+




properties c#-3.0 (7)

الاختلاف الأساسي هو أن الحقل هو موضع في الذاكرة حيث يتم تخزين البيانات من النوع المحدد. تمثل خاصية وحدة أو وحدتين من التعليمات البرمجية التي يتم تنفيذها لاسترداد أو تعيين قيمة من النوع المحدد. يتم إخفاء بناء على استخدام أساليب accessor هذه باستخدام عضو يبدو أنه يتصرف مثل حقل (في أنه يمكن أن يظهر على جانبي عملية تخصيص).

أدرك أنه يبدو مكررًا لما هو الفرق بين الحقل والممتلكات في C #؟ لكن سؤالي لديه اختلاف بسيط (من وجهة نظري):

بمجرد أن أعرف ذلك

  • لن أستخدم صفي مع "التقنيات التي تعمل فقط على الخصائص" و
  • لن أستخدم رمز التحقق من الصحة في أداة getter / setter.

هل هناك أي فرق (باستثناء أنماط التطوير / المستقبل) ، مثل نوع من التحكم في إعداد الخاصية؟

هل هناك أي فرق إضافي بين:

public string MyString { get; set; }

و

public string myString;

(أنا على علم بأن الإصدار الأول يتطلب C # 3.0 أو أعلى وأن المحول البرمجي يقوم بإنشاء الحقول الخاصة.)


الاول:

public string MyString {get; set; }

هو خاصية يشير الثاني ( public string MyString ) إلى حقل.

الفرق هو أن تقنيات معينة (ASP.NET ربط البيانات لحالات) ، يعمل فقط على خصائص ، وليس على الحقول. وينطبق الأمر نفسه على تسلسل XML: يتم إجراء تسلسل فقط للخصائص ، ولا يتم إجراء تسلسل للحقول.


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

فيما يلي قائمة بالاختلافات:

  • يمكن استخدام الحقول كمدخلات في الحجج out/ref . خصائص لا يمكن.
  • سيحقق الحقل دائمًا نفس النتيجة عندما يُطلق عليه عدة مرات (إذا تركنا مشكلات مع سلاسل عمليات متعددة). خاصية مثل DateTime.Now ليست دائما مساوية لنفسها.
  • قد تطرح الخصائص استثناءات - الحقول لن تفعل ذلك أبدًا.
  • قد يكون للخصائص تأثيرات جانبية أو يستغرق وقتًا طويلاً لتنفيذها. الحقول ليس لها أي آثار جانبية وستظل دائماً بالسرعة التي يمكن توقعها للنوع المعطى.
  • تدعم الخصائص إمكانية الوصول المختلفة للمستفيدين / المستأجرين - الحقول لا (ولكن يمكن جعل الحقول readonly )
  • عند استخدام الانعكاس ، يتم التعامل مع الخصائص والحقول على أنها أنواع MemberTypes مختلفة بحيث تكون موجودة بشكل مختلف ( GetFields vs GetProperties على سبيل المثال)
  • قد Jit Compiler معاملة الوصول إلى الخاصية بشكل مختلف جداً مقارنة بالوصول إلى المجال. ومع ذلك ، قد يتحول إلى رمز أصلي متطابق ولكن نطاق الاختلاف موجود.

الواصلون هم أكثر من المجالات. وقد أشار آخرون بالفعل إلى عدة اختلافات مهمة ، وسأضيف واحدة أخرى.

خصائص يشارك في الطبقات واجهة. فمثلا:

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 أن نقول إن مستهلكي واجهة IPerson مهتمون فقط بالحصول على الخاصية ، وليس في 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);
}

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


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

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

فكر في الخصائص مثل السكر النحوي لوظائف getXXX () / setXXX (). هذه هي الطريقة التي يتم تنفيذها وراء الكواليس.


من بين الإجابات والأمثلة الأخرى ، أعتقد أن هذا المثال مفيد في بعض المواقف.

على سبيل المثال ، لنفترض أنك تمتلك property OnChange مثل ما يلي:

public Action OnChange { get; set; }

إذا كنت ترغب في استخدام المفوضين ، فإنك تحتاج إلى تغييره إلى OnChange ليصبح مثل هذا:

public event Action OnChange = delegate {};

في مثل هذه الحالة نحمي مجالنا من الوصول غير المرغوب فيه أو التعديل.


يوجد اختلاف مهم آخر بين الحقول والخصائص.

عند استخدام WPF ، يمكنك فقط ربط الخصائص العامة. ملزمة لمجال عام لن تنجح. وينطبق هذا حتى عند عدم تطبيق INotifyPropertyChanged (حتى ولو كان يجب عليك دائمًا).





automatic-properties