برق. قدرت. کنترل. الکترونیک. مخابرات. تاسیسات.

دایره المعارف تاسیسات برق (اطلاعات عمومی برق)

حالا كه در مورد Constrcutor ها و Method ها صحبت كردیم می تونیم بگیم كه تا حدودی كلاس ها رو شناختیم و حالا می تونیم ادامه مطالبمون در رابطه با Value Type ها رو پیش ببریم:


Structures in CSharp

Structure ها نوع های داده ای هستند شبیه به كلاس ها به این معنا كه می توانند Field و Method و Constructor داشته باشند و حتی در بعضی از موارد به خاطر نوع رفتاری كه Value Type ها دارند به جای كلاس ها استفاده شوند. برای تعریف یك Structure كافیست در جایی از namespace با استفاده از keyword ی كه به همین منظور ایجاد شده است یعنی struct شروع به ایجادش نمائیم:
1
2
3
4
5
6
7
8
9
10
11
  public struct Teacher
{
public int Age;
public string Name;
public void Print()
{
Console.WriteLine("Name: {0}, Age: {1}",Name, Age);
}
}


همانطور كه می بینیم ساختار ظاهری Struct ها كاملا شبیه به كلاس است اما تفاوت اصلی آن ها در رفتارهایشان می باشد.


در تعریف
رفتار های كلاس گفتیم وقتی شما یك شیء از نوع یك كلاس مثل Person ایجاد می كنین و بعد از آن شیء كپی تهیه می كنین فقط آدرس حافظه شیء قبلی به شیء جدید اختصاص یافته و در حقیقت شما فقط یك شیء دارید.
اما در مورد Struct ها جریان كاملا شبیه به كپی گرفتن از تایپ های بدوی (Primitive Types) ها می باشد. به چند خط كد زیر دقت كنین:
1
2
3
4
5
6
7
8
9
10
  Teacher t = new Teacher();
t.Name = "Ali";
t.Age = 44;
 
Teacher t2 = t;
t2.Name = "Reza";
 
t.Print();
t2.Print();


به نظر شما خروجی این چند خط كد چیست؟

به اشكال زیر دقت كنین:





نكته بسیار مهم در شكل اول اینست كه اصولا به خاطر Value Type بودن Struct ها هیچ شیء ای در حافظه Heap ایجاد نشده است و فقط دو متغییر در حافظه Stack ایجاد شده است. نكته مهم دوم اینه كه وقتی شما از یك متغییر از نوع Struct كپی می گیرین تمامی مقادیر موجود در آن Struct كپی شده و در متغییر جدید یك كپی از آن مقادیر قرار خواهد گرفت. پس در نتیجه تغییراتی كه ما در متغییر دوم یعنی t2 دادیم برروی متغییر اول یا همان t تاثیری نخواهد داشت.


Constructors in Structures - سازنده ها در ساختار ها

نكته مهم دیگری كه می توان در مورد Struct ها بیان كرد در مورد سازنده ها در این جنس است. در پست قبلی در مورد ایجاد سازنده ها در كلاس ها صحبت كردیم و گفتم كه شما می توانین ورژن های مختلفی از سازنده ها را در یك كلاس داشته باشین. اما باید بگویم كه در مورد Struct ها جریان كمی متفاوت خواهد بود.

نكته اول: شما سازنده پیشفرض را در Struct ها دارین اما امكان تایپ كردن آن را به صورت دستی ندارین. به این معنی كه اگر شما یك Constructor بدون پارامتر در یك Struct تعریف كنین به Compile Time Error بر خورد خواهید كرد و در حقیقت شما نمی تونین هیچ تغییری در رفتار سازنده پیشفرض Struct ها ایجاد كنین. باید بدونین كه سازنده پیش فرض در Structureها در حقیقت یك object ایجاد نمی كند بلكه به تمامی متغییرهایی كه داخل Struct شما وجود دارند مقدار پیش فرض را Set می كند.
Teacher t = new Teacher();
در نتیجه كد بالا فیلد Age مقدار 0 و فیلد Name مقدار "" را كه مقادیر پیشفرض int و String هستند را خواهند گرفت.
نكته دوم: در تمامی ورژن های سازنده ها باید تمامی متغییر های Struct شما مقدار دهی شوند. در غیر اینصورت بازهم Compile Time Error خواهین داشت.
در نتیجه Struct شما می تواند به این شكل باشد:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public struct Teacher
{
public int Age;
public string Name;
 
public void Print()
{
Console.WriteLine("Name: {0},Age: {1}",Name,Age);
}
 
public Teacher(int age, string Name)
{
Name = name;
Age = age;
}
public Teacher(int age)
{
Age = age;
Name = "";
}
}

خوب البته صحبت ما در مورد Structure ها هنوز تمام نشده اما اجازه بدین ادامه مطلب رو بعد از اینكه كلاس ها رو بیشتر بررسی كردیم داشته باشیم.

نوع های در سی شارپ - Reference Type in CSharp

مهم ترین نوع داده ای Reference Type در سی شارپ همان Class یا كلاس ها می باشند كه تا حدودی در موردشان صحبت كردیم. اما یك نوع داده ای دیگر به نام object وجود دارد كه باید در موردش صحبت كنیم.

اصولا object خود نیز یك كلاس است اما به جهت اهمیتی كه دارد من آن را به صورت جدا از بقیه كلاس ها بررسی می نمایم. همانطور كه قبلا هم گفتم سی شارپ یك زبان Object Oreinted یا همان شیء گراست و تمامی مفاهیم شیء گرایی در این زبان رعایت می شود. یكی از مهمترین مفاهیم شیء گرایی مفهوم Inheritance یا همان توارث می باشد. توارث در حقیقت به معنی به ارث رفتن خصوصیات یك موجود از موجود دیگر می باشد. و نكته ای كه Inheritance رو به object ربط می دهد این است كه object به عنوان base class تمامی كلاس های موجود در دات نت فریم ورك می باشد. به این معنی كه تمامی كلاس هایی كه در دات نت فریم ورك و كلاس هایی كه شما می نویسید, همه و همه از كلاس object به ارث رفته اند.


وقتی یك كلاس از یك كلاس دیگر به ارث می رود تمامی خصوصیات عمومی آن نیز به آن كلاس به ارث می رود. مثلا اگر من كلاسی به نام Person داشته باشم كه دارای اطلاعات Name و Age و متد Print باشد وقتی كه كلاس Student را از كلاس Person به ارث می برم خصوصیات عمومی كلاس Person در كلاس Student نیز قابل استفاده می باشد.


به مثال زیر دقت كنید:

1
2
3
4
public class Test
{
}


با توجه به كدی كه بالا نوشته شده است در این كلاس هیج موجودی (اعم از Field یا Method و یا ...) وجود ندارد اما اگر از این كلاس یك شیء بسازیم متوجه می شویم كه در این كلاس یك سری متد وجود دارد:




نكته قابل تامل اینجاست كه این چهار متد (ToString(), GetHashCode(), GetType(),Equal) همگی در تمام كلاس هایی كه در دات نت یافت می شود وجود دارد. پس می توان نتیجه گرفت كه این متد ها از كلاس object به همه كلاس ها به ارث می رسند.

این كه هر كدام از این متد ها چه كاری انجام می دهند را بعد ها بیشتر توضیح خواهم داد.



رشته ها در سی شارپ - String in CSharp
نوع داده ای رشته ای نیز یكی از مهم ترین نوع های داده ایست كه در این گروه قرار می گیرد(Reference Types). برای ایجاد یك متغییر از نوع داده ای رشته ای می توانیم از نمونه كد زیر استفاده كنیم:
1
2
3
string myName = "Ali";

همانطور كه در كد بالا مشاهده می كنید برای مقدار دهی یك متغییر از نوع داده ای رشته ای كافیست مقدار مورد نظرمان را داخل دو علامت "" قرار داده و با استفاده از = مقدار دهی را انجام دهیم.
1
2
myName += "Reza";



با توجه به كد بالا مقدار myName با استفاده از operation += كه در حقیقت مقدار قبلی را + مقدار جدید كرده و مقدار دهی می نماید از Ali به AliReza تغییر یافت. البته شما می توانستید این كد را به صورت زیر نیست بنویسید:

1
2
myName = myName + "Reza";



البته دلیل ذكر مثال با روش استفاده از =+ نیست بلكه می خواهم در مورد رفتار كلاس string كمی توضیح دهم.


در حقیقت كلاس string یك كلاس از نوع Reference Type هاست اما به دلیل استفاده بسیار زیادش در زبان های برنامه نویسی مایكروسافت روش استفاده از آن را با استفاده keyword ی با همان نام و با حروف كوچك یعنی string آسانتر و به روش value type ها نموده است. به عبارت دیگر وقتی شما می نویسید:

1
2
3
string myName = "ali";


در واقع كامپایلر یك شیء از نوع string در حافظه Heap برای شما ایجاد می كند:




و وقتی مقدار قبلی را با مقدار جدید "Reza" جمع می كنین یك شیء كاملا جدید در حافظه ایجاد می شود. و شیء قبلی توسط Garbage Colletion از حافظه پاك خواهد شد.




با توجه به نكته بالا اگر در شرایطی نیاز داشتید تا یك متن را مرتبا تغییر دهید بهترین روش استفاده از string ها
نخواهد بود. چرا كه هر چه تعداد دفعات تغییر متن شما بیشتر باشد به همان میزان تعداد object های ساخته شده در حافظه Heap نیز زیاد خواهد شد (البته كه Garbage Collection آن ها را حذف خواهد كرد) اما بهتر از كلاس دیگری به نام StringBuilder برای این موضوع استفاده شود. تا به بهترین نحو از حافظه سیستم استفاده كنیم. كلاس StringBuilder در namespace System.Text قرار گرفته است و برای استفاده از آن باید یك شیء از آن بسازیم:
1
2
StringBuilder st = new StringBuilder();


و بعد می توانیم با استفاده از متد Append متن مورد نظرمان را به آن اضافه كنیم:

1
2
3
  st.Append("Ali");
st.Append("Reza");


و در نهایت با استفاده از متد ()ToString نتیجه را در غالب یك String در اختیار بگیریم:

1
2
string Name = st.ToString();


رفتار StringBuilder برخلاف رفتار String می باشد و به این ترتیب خواهد بود كه در ابتدا مثلا 16 بایت حافظه برای خودش در نظر خواهد گرفت. وقتی نصف این 16 بایت پر شده (با استفاده از دستور Append - یعنی 8 بایت) آنوقت خودش به صورت اتوماتیك یك شیء جدید خ با دو برابر اندازه فعلی در حافظه خواهد ساخت (یعنی 32 بایت) سپس مقادیر قبلی را داخل این شیء جدید كپی می گیرد. و باز وقتی نصف این 32 بایت پر شد به همین ترتیب عمل خواهد كرد. نتیجتا به صورت تساعدی این مقدار حافظه بیشتر می شود و در نتیجه تعداد اشیایی كه در حافظه ساخته می شوند كمتر و كمتر خواهد بود و در نتیجه سرعت عملكرد آن به مراتب سریعتر خواهد بود.


متد ()ToString

! دقت داشته باشین كه متد ToString از كلاس object به تمامی كلاس های دات نت به ارث می رسد. در نتیجه میتوانید از این متد هر جا كه به شكل رشته ای یك شیء نیاز داشتین استفاده كنین:
1
2
3
4
int i = 12;
int j = 32;
string myResult = (i * j).ToString();


البته دقت كنین كه همیشه اون چیزی انتظار دارین رو به شما بر نخواهد گرداند:

به عنوان مثال وقتی از شیء ای از كلاس Person را ToString كنیم (یا هر كلاسی كه شما ایجاد كرده باشید) به صورت پیشفرض خروجی ToString آن اسم كامل (Qualified Name) آن خواهد بود:
1
2
3
4
5
Person p = new Person();
p.Name = "Ali";
p.Age = 20;
Console.WriteLine(p.ToString());


یعنی اگر كلاس Person من در این مثال داخل namespaceی به نام ConsoleApplication12 باشد خروجی این مثال ConsoleApplication12.Person خواهد بود.


آرایه ها در سی شارپ - Arrays in CSharp
مسلما به مانند بیشتر زبان های برنامه نویسی استفاده از آرایه ها در سی شارپ نیز مرسوم است. استفاده از آرایه ها برای نگهداری چندین مقدار از یك نوع داده ای استفاده می شود.


آرایه ها را می توان از یك دیدگاه به سه دسته تقسیم كرد:

1. آرایه های تك بعدی - Simple Arrays
2. آرایه های مستطیلی - Rectangular Arrays
3. آرایه های نامنتظم - Jagged Arrays

برای تعریف یك آرایه تك بعدی در سی شارپ می توانید از Syntax زیر استفاده كنین:


[code]


numbers = new int[3];

numbers[0] = 100;
numbers[1] =400;
numbers[2] = 500;
[code]

همانطور كه می بینین در كد بالا من یك آرایه از اعداد ایجاد كردم كه دارای سه خانه می باشد. برای دسترسی به هر كدام از خانه های این آرایه بعد از نام متغییرم از [] استفاده می كنم و بین این دو علامت از یك عدد (indexer) كه از صفر تا n می باشد. دقت كنین كه همیشه n یكی كمتر از طول آرایه شماست.

البته به غیر از كدی كه بالا نوشته شده است من می توانم از هر یك از روش های زیر نیز برای ایجاد آرایه های استفاده كنم:
1
2
int[] numbers = new int[]{100,400,500};


در روش بالا بدون ذكر طول آرایه با مقدار دهی مستقیم آن به وسیله مقادیری كه بین دو علامت {} قرار می گیرند طول آن را مشخص می نمائیم.

این هم یك نمونه دیگر از ایجاد آرایه ها:
1
2
int numbers = {100,400,500};


نكته قابل تامل در مورد آرایه ها این است كه این نوع های داده ای در دسته Reference Type ها قرار می گیرند و اصولا مقادیر آن ها در حافظه Heap نگهداری می شود:



حالا اگر من یك آرایه از یك كلاس مثلا Person داشته باشم به نظر شما شكل حافظه این آرایه من چگونه خواهد بود؟ به كد زیر دقت كنین و سعی كنین كه شكل حافظه آن را رسم نمائید:
1
2
Person[] personList = new Person[3];


دقت كنین كه
حتما تمامی خانه های این آرایه من باید قبل از اینكه مورد استفاده بگیرند مقدار دهی شوند:
1
2
3
4
personList[0]  = new Person("Ali",24);
personList[1] = new Person("Reza",35);
personList[2] = new Person("John",44);

كه در نتیجه خطوط با شكل حافظه ما به این ترتیب خواهد بود:


نكته بسیار مهم دیگر این است كه ساختار آرایه ها به نحوی است كه طول آن ها ثابت می باشد و در صورتیكه شما بخواهید طول آن را تغییر دهید مثلا از 3 خانه به 5 خانه ارتقاء دهید باید یكبار دیگر آن را new كنید و در نتیجه این new كردن شما اطلاعات قبلی خود را از دست خواهید داد.
1
2
personList = new Person[5];


و نتیجه كد بالا این شكل خواهد شد:



پس دقت داشته باشید كه در صورتیكه می خواهید طول یك آرایه را بیشتر كنین حتما ابتدا یك آرایه جدید ساخته و طول آن را بیشتر در نظر بگیرید و سپس مقادیر آرایه قبلی را در آرایه جدید كپی كنین.


ساختار foreach در سی شارپ

شما می توانید با استفاده از ساختار foreach در سی شارپ اطلاعات موجود در آرایه های خود را خوانده و از آن ها استفاده كنین. در حقیقت foreach یك نوع حلقه است كه بر روی آرایه ها شما انجام می شود و تعداد دفعات انجام آن برابر است با طول حلقه شما و در هر با حركت یكی از خانه های آرایه شما را در اختیارتان قرار می دهد. از Syntax زیر برای ایجاد حلقه foreach استفاده می نمائیم:
1
2
3
4
5
6
int[] myNums = new int[4];
myNums[0] = 10;
myNums[1] = 320;
myNums[2] = 150;
myNums[3] = 510;


و برای نمایش اطلاعات داخل این آرایه:

1
2
3
4
foreach(int num in myNums)
Console.WriteLine(num);

!
دقت داشته باشین كه در ساختار foreach شما اجازه تغییر آرایه خود را به هر نحوی ندارید و اگر این عمل را انجام دهید به runtime error برخورد خواهید كرد.

آرایه های مستطیلی در سی شارپ - Rectangular Arrays in CSharp

برای ایجاد یك آرایه مستطیلی از Syntax زیر استفاده كنین:
1
2
int[,] myMatrix = new int[10,10];


با توجه به كد بالا شما دارای یك ماتریكس 10 در 10 هستید و برای استفاده از هر خانه از این آرایه به index های x , y آن احتیاج دارین:

1
2
3
myMatrix[0,0] = 0;
myMatrix[0,1] = 100;


و ....


آرایه های نامنتظم - Jagged Arrays

این آرایه ها را می توان با استفاده از كد زیر تولید كرد:
1
2
3
int[][] jaggedArray = new int[3][];


دقت داشته باشین كه در خط اول فقط طول یك بعد از آرایه را مشخص كردیم ==> 3

1
2
3
4
5
jaggedArray[0] = new int[3];
jaggedArray[1] = new int[2];
jaggedArray[2] = new int[4];

و در نتیجه این خطوط شما یك آرایه به مانند تصویر زیر خواهید داشت:


استفاده از ArrayList در سی شارپ - ArrayList in Csharp
به خاطر ساختار آرایه ها در سی شارپ وقتی شما نیاز به آرایه ای دارین كه طول آن نا مشخص است می توانین از یك كلاس به نام ArrayList كه در namespaceی به نام System.Collection قرار دارد استفاده كنین.
1
2
3
4
5
6
7
8
ArrayList arList = new ArrayList();
arList.Add(10);
arList.Add(20);
arList.Add(40);
 
foreach(int i in arList)
Console.WriteLine(i);


ساختار ArrayList به نحوی است كه با شروع استفاده از آن یك طول مشخصی (مثلا 4) را برای خود اختصاص می دهد. سپس وقتی شما 2 تا از این خانه ها را با استفاده از متد Add پر كنین , طول آرایه داخلی خود را به دو برابر افزایش می دهد و مقادیر قبلی را داخل آرایه جدیدش كپی میكند و این عمل را به صورت تصاعدی ادامه می دهد كه در نتیجه این عمل هم سرعت و كارایی خوبی دارد و هم طولش قابل تغییر است.



Static در سی شارپ
از یك دیدگاه می توان متغییر ها را در سی شارپ به دو دسته تقسیم كرد:

  1. Class Variable
  2. Instance Variable
تا اینجا ما چند تا مثال از نوع دوم داشتین. متغییر هایی كه باید از طریق اشیاءشان دسترسی داشت:

1
2
3
4
5
Person p = new Person();
p.Name = "Ali";
p.Age = 20;


همانطور كه می بینین برای دسترسی به Name و Age باید حتما از كلاس Person یك شیء بسازیم و از طریق شیء به متغییر ها دسترسی داشته باشیم.



اما فرض بفرمائید كه روی مفهومی مثل انسان (همان كلاس Person) می خواهیم "
جمعیت" رو پیاده كنیم. به نظر شما من می تونم رو این فرد ("Ali") مفهوم جمعیت رو پیاده كنم؟ آیا اصلا این منطقی است؟ مثل بگویم علی چند نفر است؟

به نظر می رسد كه تعریف مفهوم (متغییر) جمعیت یا تعداد روی یك فرد غیر منطقی باشد و اصولا جمعیت مربوط به كل انسان هاست نه فقط یك نفر!



برای همین ما باید از نوع اول متغییر ها استفاده كنیم كه به آنها Class Variable می گوییم برای ایجاد یك Class Variable باید از كلمه Static در تعریف متغییرمان استفاده كنیم:


1
2
3
4
5
6
7
8
9
public class Person
{
<b>public static int Count;
</b>public string Name;
public int Age;<b>
</b>}

حالا اگر بخواهم جمعیت رو مقدار دهی كنم یا اینكه مقدار جمعیت رو بخوانم باید ابتدا نام كلاس و سپس نام متغییرم رو بنویسم:

1
2
3
Person.Count = 1000;


حالا همین شرایط رو برای متد ها نیز در نظر داشته بگیرید. فرض كنین كه من می خواهم متدی داشته باشم كه جمعیت را برایم چاپ كند. آیا در تعریف این متد باید كلمه static به كار گرفته شود؟ مسلما بله! چون من می خواهم رفتاری را نشان دهم كه مربوط به كل Concept ما یا همان كلاس ماست نه مربوط به یك شیء خاص. برای همین متد PrintCount رو به صورت زیر تعریف می كنم:

1
2
3
4
5
6
public static void PrintCount()
{
Console.WriteLine("Count:{0}",Count);
}


! فراموش نكنید كه شما در متد های Static مجاز به استفاده از متغییر های غیر static نمی باشید.
وقتی می خواهیم از یك متد Static استفاده كنیم كافیست كه اسم متد رو بعد از اسم كلاس بیاوریم:

1
2
Person.PrintCount();


حالا با توجه به پست هایی كه تا امروز داشتیم, می تونین 2 تا از متد های Staticی كه استفاده كردیم رو نام ببرین؟



كلاس های Static

مفهوم كلمه Static بر روی تعریف كلاس ها به این معنی است كه وقتی شما یك كلاس Static دارین تمامی Memberهای این كلاس باید به صورت static تعریف شوند و اینكه شما
نمی توانید از این كلاس objectبسازید و البته اصولا احتیاجی به این كار هم ندارین.
در پست دوازدهم در مورد این موضوع صحبت كردیم كه در دات نت تمامی كلاس ها از یك كلاس به نام Object به ارث می روند. در این پست می خواهیم كمی در مورد Inheritance بیشتر صحبت كنیم:


توارث در سی شارپ - Inheritance in CSharp

توارث یا به ارث بری همانطور كه از اسمش پیداست به این معنی است كه شما یه سری خواص و رفتار ها را از یك كلاس دیگر (كلاس پدر - Parent Class) به ارث ببرین و در نتیجه از همان امكانات و خصوصیات بدون نوشتن دوباره آن ها استفاده كنین. و در مواردی كه لازم می دانین رفتار های آن ها را تغییر دهید. این اتفاقی است كه در دنیای واقعی نیز وجود دارد. به عنوان مثال شما احتمالا رنگ پوست , رنگ مو , رنگ چشم و شاید خصوصیات رفتاری و ... خود را از پدر و مادرتان به ارث ببرین. البته ممكن است كه شما رنگ مو خودتان را با استفاده از رنگ مو تغییر دهید یا اینكه اخلاق و رفتارتان را با توجه به افكارتان به نسبت پدر یا مادرتان متفاوت باشد.


همانطور كه در مثال بالا هم دیدیم Inheritance نیز به مانند بسیاری از اصولا Object Oriented از دنیای واقعی الگو برداری شده است و كاملا قابل درك می باشد.



فرض بفرمائید كه من یك كلاس به نام Person یا همان انسان دارم. در این كلاس خصوصیات "نام" و "سن" و همچنین یك متد به نام Print كه اطلاعات را برای من چاپ می كند , تعریف شده اند. حالا یك كلاس به نام Emp یا كارمند ایجاد می كنم. بعد از بررسی این كلاس متوجه می شوم كه كلاس Emp من دارای خصوصیات مشتركی با Person می باشد و در نتیجه تصمیم می گیرم كه به جای پیاده سازی مجدد , از امكانات كلاس Person استفاده كنم.


حالا اجازه بدین روش پیاده سازی Inheritance رو در سی شارپ بررسی كنیم.

1
2
3
4
5
6
7
8
9
10
11
12
public class Person
{
         public string Name;
         public int Age;
 
         public void Print()
        {
            Console.WriteLine("Name:{0},Age:{1}", Name, Age);
         }
}

حالا می خواهم كلاس Emp رو از كلاس Person به ارث ببرم. برای اینكار كافیه كه بعد تایپ كردن نام كلاسم یك : قرار بدهم و بعد نام كلاسی كه می خواهم از آن به ارث برم رو مشخص كنم:
1
2
3
4
public class Emp : Person
{
}


حالا اگر كدتون رو كامپایل كنین (با استفاده از Shift + Ctrl + B) و از كلاس Emp یك شیء در متد Main كلاس Programm ایجاد كنین خواهید دید كه كلاس شما دارای خواص Name و Age و متد Print می باشد.




اگر بخواهیم Class Diagram مثال فوق را رسم كنیم شكل زیر پدید خواهد آمد:



حالا به جملاتی كه من می پرسم با دقت پاسخ دهید.

1. به نظر شما یك كارمند الزما یك انسان است؟

2. می توان گفت كه هر انسان الزما یك كارمند است؟

جواب سوال اول مسلما "بله" خواهد بود. چرا كه وقتی یك كلاس (كارمند) از كلاس دیگر (انسان) به ارث می رود با اطمینان می توان گفت كه اشیاء این كلاس از جنس پدر نیز هستند.

جواب سوال دوم كاملا به شیء مورد نظر بستگی دارد و اصولا در سی شارپ این كار به صورت عادی امكان پذیر نیست.

اجازه بدین سوالات بالا رو به صورت سی شارپی ببینیم؟

1
2
3
4
5
6
7
Emp e =  new Emp();
e.Name = "Ali";
e.Age = 22;
 
Person p = e; // این كاملا در سی شارپ امكان پذیر است

اما اگر شما این كد را داشته باشید , به Compile Time Error یا همان خطاهایی كه درزمان كامپایل ایجاد میشوند بر خواهید خورد:
1
2
3
4
5
6
Person p = new Person();
p.Name = "Ali";
p.Age = 44;
 
Emp e = p; // این خط از كد خطا تولید می كند.

صحبت هامون به اونجا رسید كه گفتم شما می تونین یك شیء از نوع فرزند رو به چشم یك شیء از جنس پدر ببینید كه به این عمل اصطلاحا "Upcast" گفته می شود. یك مثال ساده هم ازش زدیم و گفتیم كه اگر شما یك كارمند داشته باشین می تونین اونو به چشم یك انسان نگاه كنین و در نتیجه از اطلاعاتی كه همه انسان ها دارند روی آن فرد خاص هم استفاده كنیم.
واقعیت این است كه وقتی شما یك شیء از جنس فرزند دارین در حافظه Heap تمامی اطلاعات موجود به آن وجود دارند ولی وقتی شما به آن شیء با Reference پدر كار كنین فقط و فقط اطلاعاتی رو می توانین استفاده كنین كه در پدر وجود دارند.

به شكل زیر نگاه كنین. كلاس Person دارای "Name"و "Age" و متد "Print" می باشد. و كلاس Emp كه از كلاس Person به ارث رفته یك فیلد به نام "Salary" نیز دارد.




حالا اگر من یك شیء از جنس Emp بسازم طبق اصولی كه گفتیم باید تمامی متد ها و field های پدر + اطلاعات خودش را داشته باشد.
1
2
3
4
5
6
Emp e = new Emp();
e.Name = "Ali";
e.Age = 45;
e.Salary = 120000;

اما اگر من یك reference به شیء "e" از جنس Person ایجاد كنم فقط و فقط می توانم اطلاعات مربوط به Person را استفاده كنم:



در واقع رفتار Compiler سی شارپ به صورت شكل زیر خواهد بود:



البته شاید این مثال كمی به نظرتون عجیب برسه! واقعیت اینه كه مثلا بالا شاید كمی غیر واقعی باشه. اجازه بدین مثالمون رو اینجوری ادامه بدیم.

فرض كنین كه شما یك متد دارین كه ورودی آن یك آرایه از اشیاء از جنس Person می باشد و بعد داخل این متد اطلاعات شیء ها را یكی یكی چاپ می كنیم:

1
2
3
4
5
6
7
public void PrintList(Person[] list)
{
      foreach(Person p in list)
        p.Print();
}

حالا شما می خواهین این متد را فراخوانی كنین ولی شما 3 شیء از جنس كارمند دارین. آیا می توانین یك آرایه از اشیایی با جنس كارمندان را به متد بالا پاس دهید؟؟؟

1
2
3
4
5
6
7
Emp = e = new Emp("Ali",34,12000);
Emp e2 = new Emp("Reza",33,10000);
Emp e3 = "Saeid",28,20000);
// ساختن یك آرایه از Person با استفاده از اشیایی از جنس Emp
<b>Person[] myList = new Person[]{e,e2,e3};</b>
<b>PrintList(myList);</b>


پس همانطور كه می بینیم عمل Upcast یكی از پر استفاده ترین اعمال در سی شارپ می باشد.


! قبلا هم گفتیم كه تمامی كلاس ها در سی شارپ از یك كلاس خاص به نام object به ارث رفته اند. حالا اگر من یك آرایه بخواهم كه بتوانم داخلش هر نوع شیء ای رو قرار بدم كافیه كه یك آرایه از جنس object بسازم و بعد هر شیء كه دوست داشتم رو داخلش قرار بدم.


در مورد Upcast توی پست قبلی صحبت كردیم. اما حالا می خواهیم در مورد DownCast صحبت كنیم.


به كد زیر دقت كنین:

1
2
3
     Emp e = new Emp("Ali",24,120000);
Person p = e;

ٍحالا فرض كنین كه من مجددا می خواهم یك Reference از جنس Emp به شیء p داشته باشم. یعنی اینكه مجددا "دیدم" رو از سطح بالا (Person) به سطح پائین تر (Emp) تغییر بدم. اینكار به صورت پیش فرض (implicit - غیر صریح) امكان پذیر نیست و در صورتیكه شما بخواهید این كار را انجام دهید حتما باید صراحتا (explicit) مسئولیت این كار را به عهده بگیرید (casting).

اجازه بدین این موضوع رو با یك مثال ساده بیشتر توضیح بدم.


یك نمایشگاه كه همه افراد اجازه بازدید دارند رو در نظر بگیرین. حالا داخل این نمایشگاه شما به یكی از افراد اشاره می كنین می گین كه شما یك كارمند هستین!! آیا این امكان پذیر است؟ مسلما نه.
مگر اینكه شما فرد مورد نظر رو بشناسین و بدانین كه ایشان یك كارمند هستند.


حالا اگر این داستان رو در دنیای برنامه نویسی هم دنبال كنیم وقتی شما یك متد دارین كه ورودی آن اشیایی از جنس Person هستند. حالا شما می خواهین یك Reference از جنس Emp به یكی از این اشیاء داشته باشین. این كار امكان پذیر نیست مگر اینكه شما مطمئن باشید كه این فرد یك كارمند
بوده و در هنگاه اجرای این متد با استفاده از Upcast وارد این متد شده است.

Casting

حالا اگر شما مطمئن بودید كه یك فرد واقعا یك كارمند است و خواستین كه عمل Downcast را انجام دهید باید مسئولیت اینكار را بعهده بگیرید. برای اینكار كافیست به صورت زیر عمل كنین:
کد:
1
2
Emp e2 = <b>(Emp)</b> p;

همانطور كه می بینین عمل Casting یا همان مسئولیت پذیری با استفاده از دو پرانتز و بعد جنس مورد نظر صراحتا اعلام شده است (explicit).

شكل حافظه زیر داستان را كاملا شفاف خواهد كرد:




همانطور كه در تصویر می بینین در DownCast در حقیقت شما "دیدتان را گسترش" می دهید و این كار هیچ تغییری در ماهیت شیء شما ایجاد نمی كند. حالا اگر شما با استفاده از Casting مسئولیت یك DownCast غیر متعبر را به عهده بگیرین با یك خطای runtime برخورد خواهید كرد:
1
2
3
     Person p = new Person("Reza", 45);
Emp e = (Emp) p;

در شكل حافظه زیر مشخص است كه عمل DownCast با شكست مواجه خواهد شد. زیر اطلاعات مورد نیاز در شیء p برای تبدیل شدن به Emp وجود ندارد.



Access Modifiers in CSharp - كنترل سطوح دسترسی در سی شارپ*
* خیلی ممنون می شم اگر كسی بتونه توی تصحیح این عبارت ها به فارسی روان تر كمكم كنه.


همانطور كه تا اینجای كار دیدین ما از دو عبارت public و private در كد هایی كه نوشتیم استفاده كرده بودیم. كه در حقیقت كنترل كننده سطح قابل دسترسی یك متغییر یا متد یا كلاس و یا ... می باشد. اگر اشتباه نكنم قبلا هم گفتم وقتی متغییری public تعریف می شود از هر جایی قابل دسترسی است. حالا اجازه بدین این موضوع رو كمی بیشتر توضیح بدهیم.


اصولا كاربرد Access Modifier ها بر روی دو حوزه (تا اینجایی كه ما اطلاعات داریم) می باشد.


1. در تعریف كلاس یا Enum یا Structure ها.

2. در تعریف متغییر ها , Method ها , Constructor ها و ...

كلا ما ۵ سطح دسترسی داریم:

public
protected
internal
protected internal یا internal protected
private

public access modifier:
به این معنی كه هیچ گونه محدودیتی قائل نیستیم. امكان استفاده از آن برای كلاس ها (آیتم های اول) و متغییر ها و ... (آیتم های دوم) وجود دارد. وقتی من كلاس public تعریف می كنم به این معناست كه هر كسی (چه داخل پروژه من و چه خارج از پروژه من) امكان استفاده از كلاس من را دارد.
وقتی متغییر یا متدی به صورت public تعریف می شود هر كسی كه به كلاس دسترسی دارد می تواند از متغییر یا متد شما استفاده كند.
!! دقت داشته باشین كه شما اجازه ندارین به متغییر ها و ... درون كلاس دسترسی بالاتر از خود كلاس بدهید.

protected access modifier:
وقتی یك متغییر یا متد یا ... به صورت protected تعریف می شوند. داخل كلاس یا ... كه تعریف شده و كلاس هایی كه از آن كلاس به ارث رفته اند قابل دسترسی می باشد.
به عنوان مثال كلاس Person دارای یك متد به نام GetInfo() است كه به صورت زیر تعریف شده است:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Person
{
   public int Age;
   public string Name;
 
   protected void GetInfo()
   {
   Console.WriteLine("Name:");
   this.Name = Console.ReadLine();
   Console.WriteLine("Age:");
   this.Age = int.Parse(Console.ReadLine());
   }
}
حالا كلاس Emp كه از كلاس Person به ارث رفته است می خواهد از متد GetInfo() استفاده كند و چون متد GetInfo() به صورت protected تعریف شده و در نتیجه تمامی كلاس هایی كه از Person به ارث بروند امكان استفاده از GetInfo() را دارند, قادر به انجام این كار است.
در صورتیكه از هیچ كجای دیگر امكان استفاده از این متد برای كلاس های دیگر مثل كلاس Programm وجود ندارد!!




! دقت داشته باشین كه protected برای گروه آیتم های اول (كلاس ها و...) قابل استفاده نیست.

internal access modifier:
خیلی از مواقع پیش می آید كه شما كلاسی را ایجاد می كنین كه احتمال دارد در پروژه های دیگری بیرون از این پروژه جاری استفاده شود. (مثلا در مورد برنامه نویسی چندلایه كه امیدوارم در آینده در موردش بیشتر توضیح بدهیم). حالا فرض فرمائین كه شما نمی خواهین یك كلاس یا متغییر یا ... آن كلاس در اختیار كسانی قرار بگیرد كه بیرون از پروژه جاری شما از این Assembly استفاده می كنند. (مثلا شما یك Component رو در نظر بگیرین كه قرار است داخل n تا پروژه دیگر استفاده شود). برای همین می توانید با استفاده از internal فقط به كلاس هایی كه داخل این پروژه شما هستند اجازه دهین كه از این كلاس یا متغییر یا ... استفاده كنند.

internal protected access modifier:
دسترسی فوق تلفیقی است از internal و protected به این معنا كه اگر متغییری به صورت internal protected تعریف شده باشد. كلاس هایی كه داخل این پروژه هستند و یا از كلاسی كه این متغییر داخلش قرار دارد به ارث رفته باشند , اجازه دارند كه از این متغییر استفاده نمایند.

! دقت داشته باشین كه protected internal هم برای گروه آیتم های اول (كلاس ها و...) قابل استفاده نیست.


private access modfier:
متغییر و یا متد و ... كه به صورت private تعریف شود , فقط و فقط داخل همان كلاس قابل استفاده خواهد بود.

! دقت داشته باشین كه private برای گروه آیتم های اول (كلاس ها و...) قابل استفاده نیست.

خصوصیات در سی شارپ - Properties in CSharp

یكی از مطالبی كه جا مونده بود بحث Properties ها در سی شارپ است. در تعریف Properties می توان گفت كه Properties یك یا دو متد است كه با یك field private كار می كند.


برای تعریف Properties ها از Synatx زیر استفاده می كنیم:
1
2
3
4
5
6
7
public string Name
{
       get{return _Name;}
       set{_Name = value;}
}
private string _Name;


همانطور كه در مثال بالا مشاهده می كنین. ما یك فیلد private به نام Name_ تعریف كردیم كه در Property ای به نام Name مورد استفاده قرار گرفته است. در حقیقت Property Name از Name_ برای ذخیره مقدار و بازیابی آن استفاده می كنند.

اما اگر Property ها از فیلد ها برای نگهداری و بازیابی اطلاعاتشان استفاده می كنند چه دلیلی دارد كه ما از property ها استفاده كنیم؟
در پاسخ به این سوال باید گفت كه به دو دلیل از Property ها استفاده می شود:

1. كنترل و مدیریت اطلاعات در حین مقدار دهی و خواندن مقادیر
در توضیح این مورد باید بگم كه اگر شما یك فیلد برای سن در نظر بگیرید و به جنس آن را از نوع عددی مثلا intتعیین كنین برنامه نویسانی كه از كلاس شما استفاده می كنند (Class Programmer ها) می توانند مقادیری بین دو عدد و برای سن مشخص كنند. اما در واقعیت این اعداد برای سن كاملا غیر معتبر می باشد. پس با اعمال كنترل های لازم در قسمت set برای Property می توان بازه ای كه برای اعداد مشخص شده است را تعیین كرد.
1
2
3
4
5
6
7
8
9
10
11
12
private int _Age;
public int Age
{
           get{return _Age;}
<b>   set{ if(!(value >= 0 && value <= 100))
               _age = 10;
           else
              _age = value;
</b>    }
}


در این مثال در صورتیكه سن بین 0 تا 100 نباشد 10 در نظر گرفته می شود.

2. امكان تعیین سطح دسترسی برای فیلد ها
نكته بعدی ایجاد Property های است كه فقط خواندنی یا فقط نوشتنی هستند. با استفاده از این روش می توانین اطلاعات را محدود به خواندن یا نوشتن نمائید تا برنامه نویسان بر اساس نیازشان فقط اطلاعات را بخوانند یا بنویسند. البته شما می توانین Property هایی كه هم خواندنی و هم نوشتنی هستند داشته باشین.
1
2
3
4
5
6
private int _Count;
public int Count
{
<b>   get{return _Count;}</b>
}

در این مثال تعداد یك Property فقط خواندنی می باشد.
! نكته ای كه می توان در سی شارپ 2.0 از آن استفاده كرد اینست كه شما می توانین برای
Property ها دو سطح دسترسی مختلف تعیین كنید :
1
2
3
4
5
6
7
public string Name
{
       get{return _Name;}
       <font color="#FF0000">protected</font> set{_Name = value;}
}


همانطور كه می بینین Property Name به صورت public تعریف شده و در نتیجه همه می توانند از آن اطلاعات بخوانند ولی برای مقدار دهی آن با توجه به protected بودن آن فقط افرادی این امكان را دارند كه از این كلاس به ارث رفته باشند. دقت كنین كه شما اجازه دارین دسترسی ها بر روی متد های get و set كمتر نمائید و حق بیشتر كردن دسترسی را ندارید.

صفحات جانبی

نظرسنجی

    لطفاً نظرات خود را درمورد وبلاگ با اینجانب در میان بگذارید.(iman.sariri@yahoo.com)نتایج تاکنون15000مفید و 125غیرمفید. با سپاس


  • آخرین پستها

آمار وبلاگ

  • کل بازدید :
  • تعداد نویسندگان :
  • تعداد کل پست ها :
  • آخرین بازدید :
  • آخرین بروز رسانی :