خواص (Properties)

property (خصوصیت) استانداردی در سی شارپ برای دسترسی به اعضای داده ای (فیلدها) با سطح دسترسی private در داخل یک کلاس می باشد. همانطور که در درس قبل اشاره شد، تعریف فیلدها در داخل کلاس به صورت public اشتباه است، چون کاربران می توانند با ایجاد یک شیء از کلاس به آنها دسترسی داشته باشند و هر مقداری که دوست دارند به آنها اختصاص دهند. برای رفع این مشکل مفهوم property ارائه شد. هر property دارای دو بخش می باشد، یک بخش جهت مقدار دهی (بلوک set) و یک بخش برای دسترسی به مقدار (بلوک get) یک داده private می باشد. property ها باید به صورت public تعریف شوند تا در کلاسهای دیگر نیز قابل دسترسی می باشند. در مثال زیر نحوه تعریف و استفاده از property آمده است :

  1: using System;
  2: 
  3: namespace PropertiesDemo
  4: {
  5:     public class Person
  6:     {
  7:         private string name;
  8:         private int age;
  9:         private double height;
 10: 
 11:         public string Name       
 12:         {                        
 13:             get                  
 14:             {                    
 15:                 return name;     
 16:             }                    
 17:             set                  
 18:             {                    
 19:                 name = value;    
 20:             }                    
 21:         }                        
 22: 
 23:         public int Age           
 24:         {                        
 25:             get                  
 26:             {                    
 27:                 return age;      
 28:             }                    
 29:             set                  
 30:             {                    
 31:                 age = value;     
 32:             }                    
 33:         }                        
 34: 
 35:         public double Height     
 36:         {                        
 37:             get                  
 38:             {                    
 39:                 return height;   
 40:             }                    
 41:             set                  
 42:             {                    
 43:                 height = value;  
 44:             }                    
 45:         }                        
 46: 
 47:         public Person(string name, int age, double height)
 48:         {
 49:             this.name = name;
 50:             this.age = age;
 51:             this.height = height;
 52:         }
 53: 
 54:     }
 55: 
 56:     public class Program
 57:     {
 58:         public static void Main()
 59:         {
 60:             Person person1 = new Person("Jack", 21, 160);
 61:             Person person2 = new Person("Mike", 23, 158);
 62: 
 63:             Console.WriteLine("Name: {0}", person1.Name);
 64:             Console.WriteLine("Age: {0} years old", person1.Age);
 65:             Console.WriteLine("Height: {0}cm", person1.Height);
 66: 
 67:             Console.WriteLine(); //Seperator                     
 68: 
 69:             Console.WriteLine("Name: {0}", person2.Name);
 70:             Console.WriteLine("Age: {0} years old", person2.Age);
 71:             Console.WriteLine("Height: {0}cm", person2.Height);
 72: 
 73:             person1.Name = "Frank"; 
 74:             person1.Age = 19;       
 75:             person1.Height = 162;   
 76: 
 77:             person2.Name = "Ronald";
 78:             person2.Age = 25;       
 79:             person2.Height = 174;   
 80: 
 81:             Console.WriteLine(); //Seperator                     
 82: 
 83:             Console.WriteLine("Name: {0}", person1.Name);
 84:             Console.WriteLine("Age: {0} years old", person1.Age);
 85:             Console.WriteLine("Height: {0}cm", person1.Height);
 86: 
 87:             Console.WriteLine();
 88: 
 89:             Console.WriteLine("Name: {0}", person2.Name);
 90:             Console.WriteLine("Age: {0} years old", person2.Age);
 91:             Console.WriteLine("Height: {0}cm", person2.Height);
 92:         }
 93:     }
 94: }
Name: Jack
Age: 21 years old
Height: 160cm

Name: Mike
Age: 23 years old
Height: 158cm

Name: Frank
Age: 19 years old
Height: 162cm

Name: Ronald
Age: 25 years old
Height: 174cm

در برنامه بالا نحوه استفاده از property آمده است.همانطور که مشاهده می کنید در این برنامه ما سه فیلد (خطوط 9-7) تعریف کرده ایم (سه فیلد با سطح دسترسی private).

private string name;
private int age;
private double height;

دسترسی به مقادیر این فیلدها فقط از طریق property های ارائه شده (خطوط 45-11) امکان پذیر است.

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

public int Age
{
    get
    {
        return age;
    }
    set
    {
        age = value;
    }
}

public double Height
{
    get
    {
        return height;
    }
    set
    {
        height = value;
    }
}

وقتی یک خاصیت ایجاد می کنیم ، باید سطح دسترسی آن را public تعریف کرده و نوع داده ای را که بر می گرداند یا قبول می کند را مشخص کنیم. به این نکته توجه کنید که نام property ها همانند نام فیلدهای مربوطه می باشد با این تفاوت که حرف اول آنها بزرگ نوشته می شود. البته یادآور می شویم که شباهت نام property ها و فیلدها اجبار نیست و یک قرارداد در سی شارپ می باشد.

به کلمه کلیدی value در داخل بلوک set توجه کنید. Value همان مقداری است که از طریق property به فیلد اختصاص می دهیم. برای اختصاص یک مقدار به یک فیلد از طریق property کافیست که به صورت زیر عمل کنید :

Object.Property = Value;

این کار (قرار دادن یک مقدار بعد از علامت مساوی) به منزله فراخوانی بخش set است. و ما به برنامه می فهمانیم که می خواهیم از طریق بخش set یک فیلد را مقداردهی کنیم. Object شیء ایجاد شده از کلاس، Property نام پراپرتی و Value مقداری است که می خواهیم به فیلد اختصاص دهیم. برای دسترسی به یک خاصیت می توانید از علامت دات (.) استفاده کنید. مثلا برای اختصاص مقدار به سه فیلد age، name و height از طریق property باید به صورت زیر عمل کنید :

person1.Name = "Frank";
person1.Age = 19;
person1.Height = 162;

دستورات بالا بخش set مربوط به هر property را فراخوانی کرده و مقادیری به هر یک از فیلدها اختصاص می دهد. برای فراخوانی بخش get کافیست که نام شیء و سپس علامت نقطه و در آخر نام property را بنویسیم. با این کار به برنامه می فهمانیم که ما نیاز به مقدار فیلد داریم.

Console.WriteLine("Name: {0}", person1.Name);
Console.WriteLine("Age: {0} years old", person1.Age);
Console.WriteLine("Height: {0}cm", person1.Height));

به این نکته توجه کنید که در بخش get هم می توان تغییراتی بر روی فیلدها اعمال کرد. مثلا فرض کنید که یک فیلد دارید که مقادیر پولی را در خود ذخیره می کند. شما می توانید در بخش get نحوه نمایش مقدار موجود در این فیلد را مشخص کنید. مثلا خروجی به صورت سه رقم سه رقم نمایش داده شود. استفاده از property ها کد نویسی را انعطاف پذیر می کند مخصوصا اگر بخواهید یک اعتبارسنجی برای اختصاص یک مقدار به فیلدها یا استخراج یک مقدار از آنها ایجاد کنید. پس می توان گفت که :

مثلا شما می توانید یک محدودیت ایجاد کنید که فقط اعداد مثبت به فیلد age (سن) اختصاص داده شود. همانطور که در کد ابتدای درس مشاهده می کنید ما نوع فیلد age را int قرار داده ایم. یعنی کاربر می تواند هر رقمی بین اعداد 2147483648- تا 2147483647 را به این فیلد اختصاص دهد. ولی چون غیر معقولانه است و سن (age) باید یک عدد مثبت و از لحاظ عقلی عددی از 1 تا 100 باشد می توانیم کاربر را با استفاده از بخش set مجبور کنیم که رقمی بین این دو عدد را به age اختصاص دهد. می توانید با تغییر بخش set خاصیت Age این کار را انجام دهید :

  1: public int Age           
  2: {                        
  3:     get                  
  4:     {                    
  5:         return age;      
  6:     }                    
  7:     set                  
  8:     {                    
  9:         if (value > 0 && value <= 100)
 10:         age = value;                  
 11:         else                          
 12:         age = 0;                      
 13:     }                    
 14: }

حال اگر کاربر بخواهد یک مقدار منفی به فیلد age اختصاص دهد مقدار age صفر خواهد شد. همچنین می توان یک property فقط خواندنی (read-only) ایجاد کرد. این property فاقد بخش set است. به عنوان مثال می توان یک خاصیت Name فقط خواندنی مانند زیر ایجاد کرد :

public string Name
{
    get
    {
        return name;
    }
}

در این مورد اگر بخواهید یک مقدار جدید به فیلد name اختصاص دهید با خطا مواجه می شوید. نکته دیگری که باید به آن توجه کنید این است که شما می توانید برای بخش set یا get سطح دسترسی ایجاد کنید. به تکه کد زیر توجه کنید :

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

خاصیت Name فقط در خارج از کلاس قابل خواندن است اما متدها فقط داخل کلاس Person می توانند مقادیر جدید بگیرند. یک property می تواند دارای دو فیلد باشد. به کد زیر توجه کنید :

private string firstName;
private string lastName;

public FullName
{
   get { return firstName + " " + lastName; }
}

همانطور که در مثال بالا مشاهده می کنید یک property فقط خواندنی تعریف کرده ایم که مقدار برگشتی آن ترکیبی از دو فیلد firstName و lastName است که به وسیله فاصله از هم جدا شده اند. سی شارپ همچنین یک راه حل کوتاه برای ایجاد property ارائه می دهد. در این روش می توانید یک property بدون فیلد ایجاد کنید. گاهی اوقات ممکن است که شما اصلا نخواهید اعتبار سنجی انجام دهید. در این صورت بهتر است که آینده نگر باشید و باز هم به ازای هر فیلد موجود در کلاس یک خاصیت تعریف کنید. البته برای کاهش کدنویسی، می توانید از نوع خلاصه شده property ها یعنی property های خودکار استفاده کنید :

public int MyProperty { get; set; }

این ویژگی فراخوانی خودکار property نام دارد و در سی شارپ 3٫0 معرفی شده است. به این نکته توجه کنید که در این روش هیچ کدی برای بخش set و get نمی نویسیم. دستور بالا معادل تعریف یک فیلد از نوع int با سطح دسترسی private است و property مربوط در یک خط مختصر نوشته شده و اجرا می شود. کامپایلر کد بالا را به صورت خودکار به عنوان یک property شناسایی می کند و فیلد مربوط به آن در طول زمان اجرای برنامه ساخته می شود. توجه کنید وقتی یک property خودکار ایجاد می کنید باید هر دو بخش get و set آن را نیز تعریف کنید. همچنین نباید هیچ کدی در داخل این دو بخش بنویسید. بعدها اگر لازم بود که برای فیلدها اعتبارسنجی صورت بگیرد، می توانید بدون اینکه کدی که از کلاس استفاده می کند نیاز به تغییری داشته باشد، property های خودکار را به صورت property های معمولی ولی با اعتبارسنجی بنویسید.

لطفا اگر نظر، پیشنهاد و یا انتقادی در باره مطلب بالا دارید در قسمت زیر و اگر سوالی دارید در بخش پرسش و پاسخ مطرح بفرمایید.

  1. علیرضا پاسخ دادن

    سلام….سوالی داشتم…
    میخواستم بدونم آیا یک property می تواند فاقد بخش set باشد…؟
    type آورده شده قبل از مغرفی property همان تایپ برگشت است یا این دلیل دیگری دارد…؟
    آیا یک property می تواند فقط بخش set داشته باشد و مقدار برگشتی نداشته و بجای تایپ در هیدر معرفی یک prpperty عبارت void را بگذاریم…؟

    • Developer0400 پاسخ دادن

      سلام دوست عزیز ، لطف کنید سوالات خود را در بخش فروم سایت بپرسید . بله یک Property رو هم میشه به صورت Read-Only ( فقط بخش get داشته باشه) یا اینکه به صورت Write-Only ( فقط بخش Set ) داشته باشه ، تعریف کرد .

      کافیه فقط بلاک set یا get رو حذف کنید .

      • محمد پاسخ دادن

        و البته میتونیم از نوع private تعریف کرد هر کدوم رو

        • یونس ابراهیمی

          سلام ، ممنون از نظرتون دوست خوبم

          بله میشه هر نوع سطح دسترسی رو تعیین کرد ولی عموما و بیشتر مواقع Property ها رو به صورت Public نعریف می کنند .

  2. داود پاسخ دادن

    سلام. [واستم بابت این مطلب از شما تشکر کنم. من یونیتی کار میکنم و این مطلب شما خیلی به ردر من خورد.

    • یونس ابراهیمی پاسخ دادن

      ممنون دوست عزیز، لطف دارین

  3. Matin پاسخ دادن

    سلام
    ببخشید یه سوال واسم پیش اومد
    این Property خودکاری که ایجاد میشه حالا به چه دردی میخوره ، ینی کاربردش چیه و اگه بعنوان فیلد میخاد استفاده بشه خوب چه نیازی به اینه که یه Property درست کنیم ،همون اول یه فیلد تعریف میکنیم.من یه مبتدی هستم و اگه میشه لطفا جوابمو کامل بدید.مچکرم .

  4. یونس ابراهیمی پاسخ دادن

    سلام، خواهش می کنم
    ممنون میشم سوالتونو تو بخش پرسش و پاسخ سایت مطرح بفرمایید

  5. Matin پاسخ دادن

    ببخشید اصلا نمیخاستم نظم اینجا به هم بخوره اما نمیدونم کجا رو میگید لطفا لینک بدید ممنون

  6. محسن کیت پاسخ دادن

    سلام
    عالی بود
    مرسی

  7. پریناز پاسخ دادن

    سلام خسته نباشید ببخشید من این درس رو چند بار خوندم ولی متوجه نشدم دقیقا لزوم استفاده از پراپرتی واینکه چه مواقع از پراپرتی برای تعریف متغیرهامون استفاده میکنیم در کد بالا هم چند جا متوجه نمیشم چرا به دو صورت متغیرها تعریف شدن ودرآخر چرا به دوشکل مقدار دهی شدند اگر مطلبی هست برای روشن شدن بیشتر این مطلب معرفی کنید برام ممنونونتون میشم ببخشید طولانی شد

  8. پریناز پاسخ دادن

    سلام ببخشید من جوابی دریافت نکردم میشه راهنمایی کنید ممنون میشم اگه جوابمو همین جا بدید

    • یونس ابراهیمی پاسخ دادن

      سلام دوست عزیز
      شما خوب نخوندین که خوب متوجه نشدین، اول اینکه به دو صورت تعریف و مقدار دهی نمیشن، تو متن بالا گفتیم که اگه کلاسی یه فیلد داشته باشه یه پراپرتی هم نام با اون ایجاد می کنیم و این نام هم باید با حرف بزرگ شروع بشه و قراردادیه. در مورد کاربرد اصلی پراپرتی ها هم تو اون کادر زرد رنگ نوشتیم، اینکه عرض می کنم خوب نخوندین قبول کنید، نوشتیم که کاربرد اصلیش اعتبار سنجی مقادیری است که کاربر می خواهد به فیلدها اختصاص دهد. حتی مثال زدیم که فرض کنید یه فیلد سن دارید و میخواهید کاری کنید که کاربر مقداری بین ۱-۱۰۰ رو به اون اختصاص بده. این فیلتر گذاری با پراپرتی ها انجام میشه. من توصیه می کنم یه بار دیگه بخونید.
      در آخر هم ممنون میشم سوالاتتونو تو بخش پرسش و پاسخ مطرح بفرمایید.
      با تشکر

  9. پریناز پاسخ دادن

    ممنونم از پاسخ وتوضیحی که دادید چشم حتما میخونم

    • یونس ابراهیمی پاسخ دادن

      خواهش میکنم