شی گرایی پیشرفته سی شارپ
در جلسهی قبل با مبحث شی گرایی در کنار شما بودیم و در این قسمت با بررسی مبحث Listهای دادهای و تکمیل کردن مبحث شی گرایی در کنار شما هستیم.
شی گرایی پیشرفته در سی شارپ
معرفی Listها
در صورتی که بخواهید یک تعداد داده به طور متوالی داشته باشید اکثر به دنبال آرایه میروید؛ همانطور که میدانید تعداد سلولهای آرایه ثابت است و امکان تغییر تعداد سلولها یک آرایه بهصورت پویا وجود ندارد. اما تعداد عناصر List به صورت پویا میتواند تغییر کند. با استفاده از List نیازی نیست که اندازهی آن را ابتدای کار مشخص شود. در واقع با استفاده از List آرایهای میسازیم که اندازهی آن ثابت نیست. List در فضای نام using System.Collections.Generic قرار دارد.
فرم کلی آن به شکل زیر است:
List <Datatype> ListName = new List <Datatype>();
مثال:
List <int> list = new List <int>(); list.Add(52); list.Add(124); list.Add(5); list.Add(19); list.Add(85);
مثال:
class Car
{
public string Color;
public string Model;
public int MaxSpeed;
public Car(string carColor, string carModel, int carMaxSpeed)
{
Color = carColor;
Model = carModel;
MaxSpeed = carMaxSpeed;
}
}
// Using :
List<Car> CarCollection = new List<Car>();
CarCollection.Add(new Car (“Red", "BMW", 200));
CarCollection.Add(new Car (“Blue", "Benz", 250);
CarCollection.Add(new Car (“White", “Toyota", 180));
string NamColor = CarCollection[0].Color;
string NamModel = CarCollection[0].Model;
int MaxSpeed = CarCollection[0].MaxSpeed;
مبحث Collectionها
با کمک collectionها میتوانیم کلکسیونی از کلاسها را ایجاد کنیم. به عنوان مثال میتوان کلاسی ایجاد کرد که آن خوداز چندین نمونه، از کلاسهای ایجاد شود. این کلاس خصوصیاتی مانند حذف و اضافه نمونهها از کلکسیون را دارا است. Collection در فضای نام using System.Collections قرار دارد. هنگام تغریف Collection باید از کلمه CollectionBase در مقابل نام Collection استفاده کنیم (باید از CollectionBase ارثبری کنیم).
مثال:
public class Car
{
public string Color;
public string Model;
public int MaxSpeed;
public Car(string carColor, string carModel, int carMaxSpeed)
{
Color = carColor;
Model = carModel;
MaxSpeed = carMaxSpeed;
}
}
public class My_cars : CollectionBase
{
public void Add(Car new_car)
{
List.Add(new_car);
}
public void Remove(Car old_car)
{
List.Remove(old_car);
}
}
public class Car
{
public string Color;
public string Model;
public int MaxSpeed;
public Car(string carColor, string carModel, int carMaxSpeed)
{
Color = carColor;
Model = carModel;
MaxSpeed = carMaxSpeed;
}
}
public class My_cars : CollectionBase
{
public void Add(Car new_car)
{
List.Add(new_car);
}
public void Remove(Car old_car)
{
List.Remove(old_car);
}
}
در مثال بالا دو کلاس تعریف شده است. اولین کلاس، کلاس Car است که ویژگیهای یک عنصر از کلکسیون کلاس ما میباشد. دومین کلاس، کلکسیون کلاس است (My_cars) که شامل مجموعهای از اشیاء از نوع کلاس Car است. کلاس CollectionBase دارای خاصیت List است که مجموعهای از اشیاء را در خود جای میدهد. همچنین دارای متدهایی مانند Add و Remove و… برای حذف یا اضافه کردن و … اشیاء است و به سادگی میتوان با استفاده از خاصیت List و متد مربوطه عملیلات مورد نظر را انجام داد. نیازی به تعریف یک لیست از نوع کلاس نمیباشد زیرا خود داری خاصیت List می باشد.
نکته: متدهای خاصیت List یک شیء را قبول میکنند نه یک کلاس را.
نحوه استفاده:
My_cars mycar = new My_cars(); mycar.Add(new Car("Red", "BMW", 200)); mycar.Add(new Car("Blue", "Benz", 250));
کاربرد کلمهی کلیدی static
عضوی از کلاس که بدون ساخت هیچ شیءای، مستقیماً (از طریق نام کلاس و عملگر نقطه) میتوانید به آن دسترسی داشته باشید. آن عضو بدون ساخت هیچ objectای از کلاس قابل دسترسی و در واقع مستقل از اشیاء است؛ میتوانید هم متدها و هم متغیرها را بهصورت static تعریف کنید. از آنجا که متد ()Main نقطهی شروع برنامه و یکی از اعضای کلاس است. باید قبل از هرچیز و پیش از ساخت هرگونه شیءای، صدا زده شود. لذا متد ()Main را بهصورت static تعریف میکنیم.
class MyClass {
public static int Variable = 100;
public static int MyMethod()
{
return Variable + 20;
}
}
MyClass.Variable = 8; MyClass.MyMethod();
نکته: متد static تنها میتواند به اعضای static دسترسی داشته باشد و نمیتواند مستقیماً به اعضای عادی کلاس دسترسی پیدا کند. زیرا اعضای عادی یک کلاس حتماً باید به یک شیء وصل شوند تا مقدارشان در آن شیء ذخیره شود؛ اگر قصد دارید درون یک متد static به اعضای عادی نیز دسترسی داشته باشید.
باید از طریق یک شیء اینکار را انجام دهید:
class MyClass {
public void NonStaticMethod()
{
Console.WriteLine("This is a non static method");
}
public static void StaticMethod(MyClass Mclas)
{
Mclas.NonStaticMethod(); // this is ok
}
}
کلاسهایی از نوع static
هنگامیکه یک کلاس را بهصورت static تعریف میکنید دیگر نمیتوانید از روی این کلاس شیء بسازید و همهی اعضای کلاس باید static باشند.
static class Calculator {
public static double Add(double a, double b)
{
return a + b;
}
public static double Subtract(double a, double b)
{
return a - b;
}
}
برای استفاده از کلاس بالا نیازی ندارید که از آن شیء بسازید و با استفاده از نام خود کلاس میتوانید از آن استفاده کنید.
مثال:
ابتدا یک شیء از این کلاس ساخته و مقادیر را به آن میدهیم. فیلدهای private خارج از کلاس خودشان در دسترس نیستند. ما از طریق یک متد public توانستیم مقدار آنها را به خارج از کلاس ارسال کنیم. خب بعد از پایان این بحثهای پیش نیاز به ادامهی بحث شیگرایی که در جلسه قبل به آن پرداختیم میپردازیم.
کپسوله سازی یا Encapsulation
Encapsulation در سیشارپ بدین معناست که اطلاعات یک کلاس در برابر دسترسیهای غیرمجاز و خرابکاری محفوظ نگه داشته شود.
این ویژگی اساسی شی گرایی حاوی دو مزیت اصلی است:
- اینکه دادهها را به کدهای درون کلاس متصل میکند.
- اینکه دسترسی به اعضای کلاس را کنترل میکند.
کنترل دسترسی از طریق access modifierها انجام میشود که public، private، protected و internal هستند.
فرستادن Reference به متدها
پارامترهای ورودی همیشه حتما نباید متغیرها و دادههای ساده باشد گاهی نیاز داریم. به متد Reference خاصی ارسال کنیم و در آن از آن Reference استفاده کنیم.
مثال:
class MyClass
{
string Name;
string Surname;
int Age;
public MyClass(string name, string surname, int age)
{
Name = name;
Surname = surname;
Age = age;
}
public bool SameAs(MyClass ob)
{
if (Name == ob.Name && Surname == ob.Surname && Age == ob.Age)
return true;
else
return false;
}
public void Copy(MyClass ob)
{
Name = ob.Name;
Surname = ob.Surname;
Age = ob.Age;
}
public void Show() {
Console.WriteLine(" Name: {0}, Surname: {1}, Age: {2}", Name, Surname, Age);
}
}
// Using :
MyClass ob1 = new MyClass("Damon", "Salvatore", 22);
MyClass ob2 = new MyClass("Stefan", "Salvatore", 21);
Console.WriteLine("ob1: ");
ob1.Show();
console.WriteLine("ob2: ");
ob2.Show();
if (ob1.SameAs(ob2))
Console.WriteLine("ob1 and ob2 have the same values.");
else
Console.WriteLine("ob1 and ob2 have different values."); // Now, make ob1 a copy of ob2
ob1.Copy(ob2);
Console.WriteLine();
Console.WriteLine("ob1 after copy: ");
ob1.Show();
if (ob1.SameAs(ob2))
Console.WriteLine("ob1 and ob2 have the same values.");
else
Console.WriteLine("ob1 and ob2 have different values.");
نکته: به همان روشی که value typeها به متدها داده میشوند، reference typeها نیز به متدها داده شدهاند.
ارسال آرگومان به پارامترها
از دو طریق Argumentها به parameterها فرستاده میشوند:
- Call-by-value
- Call-by-reference
در روش اول call-by-value از مقدار argument یک کپی گرفته شده و به پارامتر داده میشود. از اینرو، هر کاری که با پارامتر کنید هیچ تغییری روی argument صورت نمیگیرد.
مثال:
static void Change(int x)
{
x++;
}
int a = 5;
Change(a);
در روش دوم call-by-reference یک reference بهعنوان argument به متد داده شده و کپی این reference به پارامتر فرستاده میشود. درون متد، پارامتر به همان شیءای رجوع میکند که argument رجوع میکند. این یعنی اگر هر تغییری روی پارامتر انجام دهید، این تغییر روی argument نیز تاثیر میگذارد زیرا هردو به یک شیء وصل هستند. تغییر هرکدام، شیء را تحت تاثیر قرار میدهد.
مثال:
class Test
{
public int a, b;
public Test(int i, int j)
{
a = i;
b = j;
}
public void Change(Test ob)
{
ob.a = ob.a + ob.b;
ob.b = -ob.b;
}
}
// Using :
Test ob = new Test(15, 20);
Console.WriteLine("ob.a and ob.b before call: " + ob.a + " " + ob.b);
ob.Change(ob);
Console.WriteLine("ob.a and ob.b after call: " + ob.a + " " + ob.b);
خب این هم از جلسهای جدید در دورهی آموزشی سی شارپ امیدوارم لذت ببرید.
برای استفاده از تمامی جلسات از هشتگ #دوره آموزشی_سی_شارپ در سایت ما استفاده کنید.
منتظر جلسهی بعدی دوره آموزشی سی شارپ بمانید.



















تو طراحی پروژههای بزرگ، استفاده از interface بهتره یا کلاسهای والد انتزاعی؟
در پروژههای بزرگ، اگر فقط نیاز به تعریف قرارداد (یعنی امضای متدها و ویژگیها) داری و میخوای کلاسهای مختلف از چندین منبع بتونن اون قرارداد رو پیادهسازی کنن، استفاده از interface بهتره چون چندارثبری برای اینترفیسها در سیشارپ ممکنه ولی برای کلاسها نه. اما اگر بخوای پیادهسازی مشترک یا منطق پایهای داشته باشی که همه کلاسها ازش استفاده کنن، abstract class انتخاب بهتریه. در واقع ترکیب این دو رو بسته به نیاز معماری میتونن استفاده کنی.
استفاده از abstract تو کلاسها چه مزیتی نسبت به virtual داره؟
متدهای abstract در کلاسهای انتزاعی هیچ پیادهسازیای ندارن و اجباری هست که در کلاسهای مشتق شده پیادهسازی بشن، در حالی که متدهای virtual پیادهسازی پیشفرض دارن و میتونن در صورت نیاز در کلاسهای فرزند بازنویسی (override) بشن یا نشن. این یعنی abstract تضمین میکنه که هر کلاس فرزند حتما باید متد رو تعریف کنه، ولی virtual اختیاریه.
تفاوت بین override و new دقیقاً چیه؟
وقتی میخوای رفتار یک متد والد رو در کلاس فرزند تغییر بدی، از override استفاده میکنی که به سیشارپ میگه متد والد رو جایگزین کن. اما وقتی از new استفاده میکنی، یک متد جدید با همون اسم توی کلاس فرزند ایجاد میکنی که سایه میاندازه روی متد والد، ولی اگر شیء از نوع کلاس والد داشته باشی، متد والد اجرا میشه (یعنی پنهانسازی، نه بازنویسی). پس override برای تغییر رفتار واقعی متد والد استفاده میشه، new برای مخفی کردن متد والد.
اگه تو یه کلاس چند لایه ارثبری داشته باشیم، کدوم constructor اول اجرا میشه؟
در ارثبری چند لایه، وقتی شیئی ساخته میشه، اول سازنده کلاس والد بالا دست (بالاترین سطح) اجرا میشه و بعد به ترتیب به سمت پایینتر (کلاس فرزند) میآید. یعنی ابتدا سازنده پایهترین کلاس اجرا میشه و سپس سازنده کلاسهای فرزند به ترتیب سلسلهمراتبی اجرا میشن تا نهایتا سازنده کلاس فعلی. این ترتیب تضمین میکنه که همه اعضای پایه قبل از کلاس فرزند مقداردهی میشن.
این جلسه ارث بری و چندریختی خیلی کاربردی توضیح داده شده
موفق باشید.