در مقالات قبلی، ما کلاسها، نحوه استفاده از آنها و نحوه ایجاد یک آبجکت به عنوان نمونه ای از کلاس را یاد گرفتیم. در این مقاله، ما میخواهیم در مورد ساختارها که شبیه کلاسها هستند ولی با تعدادی تفاوت صحبت کنیم.
این مقاله، سرفصلی از دوره آموزشی زیر میباشد:
- کلاسها و سازنده ها
- ویژگیها
- constant ،Static member ها و Extension Method ها
- Anonymous Type ها و Nullabel Type ها
- ساختارها
- شمارنده ها
- وراثت
- Interface ها
- کلاسهای Abstract
- Generic ها
- Queue, Stack, Hashtable
- Generic List و Dictionary
- Delegate ها
اگر می خواهید محتویات کامل این دوره را ببینید ، می توانید بر روی لینک سطح متوسطه #C کلیک کنید.
برای دانلود سورس، رو لینک سورس ساختارها در #C کلیک کنید.
ما این مقاله را به قسمتهای زیر تقسیم میکنیم:
- کار با ساختارها
- تعریف ساختار
- تفاوتهای بین کلاسها و ساختارها
- زمان استفاده از ساختار به جای کلاس
- نتیجه گیری
کار با ساختارها
یک ساختار بر خلاف یک کلاس که reference type است یک value type میباشد و مانند یک کلاس، فیلدها، متدها و سازنده های خودش را دارد.
شاید شما متوجه این قضیه نشده باشید که ما در مقالات قبلی به خصوص در ماژول 1 مبانی #C با ساختارها کار کردیم. نوعهای Int, double, decimal, bool و غیره همگی نام مستعاری از ساختارهای System.Int32, System.Int64 و غیره هستند. در جدول زیر، ما میتوانیم نوعهای اصلی و اینکه از چه چیزی (ساختار یا کلاس) ساخته شده اند را ببینیم:
تعریف ساختار
برای تعریف ساختار، ما باید از کلمه کلیدی struct و به دنبال آن، نام نوع مورد نظر و سپس بدنه ساختار بین بریس باز و بسته استفاده کنیم:
1 2 3 4 |
public struct Time { private int _hours, _minutes, _seconds; } |
ما میتوانیم از سازنده، برای مقداردهی اولیه فیلدهای private استفاده کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public struct Time { private int _hours, _minutes, _seconds; public Time(int hours, int minutes, int seconds) { _hours = hours; _minutes = minutes; _seconds = seconds; } public void PrintTime() { Console.WriteLine($"Hours: {_hours}, Minutes: {_minutes}, Seconds: {_seconds}"); } } |
سپس برای دسترسی به ساختارمان، میتوانیم از سینتکس زیر استفاده کنیم:
1 2 3 4 5 6 7 |
static void Main(string[] args) { Time time = new Time(3, 30, 25); time.PrintTime(); Console.ReadKey(); } |
تفاوتهای بین ساختارها و کلاسها
- ساختار یک value type است در حالیکه کلاس یک reference type است.
- ما سازنده پیشفرض مان را نمیتوانیم در یک ساختار تعریف کنیم، به این دلیل که یک ساختار همیشه یک سازنده پیشفرض برای ما تولید میکند. ولی در یک کلاس، میتوانیم سازنده پیشفرضمان را ایجاد کنیم، چرا که یک کلاس برای ما آن را تولید نمیکند.
- ما میتوانیم فیلدها را در در ساختارمان با ایجاد یک سازنده غیرپیشفرض، مقداردهی اولیه کنیم، اما حتما باید همه آن فیلدها را مقداردهی کنیم. ساختار اجازه نمیدهد که هیچ یک از فیلدها را بدون مقدار رها کنیم.
در صورتی که در کلاس، همچین چیزی نیست.
- در یک کلاس، ما میتوانیم فیلدها را در همان نقطه تعریفشان، مقداردهی اولیه کنیم. در صورتی که در یک ساختار نمیتوانیم همچین کاری را انجام دهیم:
- یک نمونه از یک کلاس بر روی یک حافظه heap ثبت میشود در حالیکه یک نمونه از یک ساختار بر روی یک stack ثبت میشود.
- در یک ساختار، ما میتوانیم یک سازنده غیرپیشفرض ایجاد کنیم، اما با این وجود، کامپایلر همیشه یک سازنده پیشفرض نیز برای ما تولید میکند. اما همچین چیزی در مورد کلاسها صدق نمیکند.
زمان استفاده از ساختار به جای کلاس
قاعده کلی که می توانیم از آن پیروی کنیم این است که ساختارهای ما باید نوعهای کوچک و ساده ای باشند و بیش از هر چیز تغییرناپذیر باشند. برای هرچیز به غیر از این، باید از کلاس استفاده کنیم.
چرا تغییرناپذیر خیلی مهم است؟
خب اجازه دهید یک نگاهی به این مثال بیندازیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Test { public int Number { get; set; } public Test(int number) { Number = number; } } class Program { static void Main(string[] args) { Test test = new Test(10); Console.WriteLine(test.Number); ChangeNumber(test); Console.WriteLine(test.Number); } public static void ChangeNumber(Test test) { test.Number = 45; } } |
اگر ما نتیجه را بررسی کنیم، میبینیم که در خروجی 10 و 45 چاپ میشود و این نتیجه درستی است. اما اگر این کلاس را به یک ساختار تغییر دهیم و سپس نتیجه را بررسی کنیم، نتیجه 10 و 10 خواهد بود. این خود میتواند منجربه سردرگمی و مشکلاتی نیز شود، زیرا استفاده کننده از ساختار ممکن است انتظار داشته باشد که متد ChangeNumber ویژگی Number را باید تغییر دهد چرا که ما اجازه این تغییر را در کد داده ایم. اما اگر ما ویژگیها یا فیلدها را به طور غیرقابل تغییر ایجاد کنیم (به عنوان فقط خواندنی در یک ساختار)، آنگاه می توانیم از این نوع سردرگمی جلوگیری کنیم. استفاده کننده ساختار میتواند با فراخوانی متد سازنده، مقادیر را به ویژگیها تخصیص دهد اما بعد از آن، ویژگیها باید غیرقابل تغییر باقی بمانند.
نتیجه گیری
در این مقاله، ما یاد گرفتیم:
- ساختار چیست و نحوه ایجاد آن چگونه است
- محدودیتهای استفاده از ساختار چه چیزهایی است
- چه زمانی از ساختارها در کد استفاده کنیم
در مقاله بعدی ما در مورد شمارنده ها در #C صحبت میکنیم.