خلاصه: در این آموزش با متغیرهای #C از جمله اعلان متغیرها(declaring variables)، تخصیص مقادیر(assigning values) به متغیرها و نمایش متغیرها در console آشنا خواهید شد.
برنامه ها داده ها را پردازش می کنند. به طور معمول، به صورت زیر عمل می کند:
برای ذخیره داده ها در حین اجرای برنامه از متغیرها استفاده می کنید.
طبق تعریف، متغیرها شناسه هایی(identifiers) هستند که مقادیر آنها در طول اجرای برنامه می تواند تغییر کند. هنگامی که برنامه به پایان می رسد، مقادیر ذخیره شده در متغیرها نیز از بین می روند.
type variableName;
در این syntax:
دسته Integers :
تعدادی از data typeهای مختلف برای نمایش اعداد استفاده می شود. هر کدام در محدوده مجاز خود متفاوت هستند، بنابراین باید هنگام تصمیم گیری در مورد استفاده از هر کدام با توجه به موقعیت پیش رو برنامه ریزی کنید.
دسته Floating Points :
سه نوع مختلف از اعداد ممیز شناور وجود دارد. هر کدام از نظر range، performance و دقت(precision) متفاوت هستند.
دسته Objects :
خوب object built-in type نام مستعار NET framework Object. است که تمام کلاس های دیگر از آن مشتق شده اند. نوع object این توانایی را دارد که از طریق فرآیندهای boxing و unboxing شکل هر type دیگری را به خود بگیرد و به type گفته شده تبدیل شود.
بیایید به مثالی از یک object نگاه کنیم که به شکل چندین built-in type دیگر است. این مزیت اصلی استفاده از یک نوع object است. یک نقطه ضعف استفاده از object type این است که زمان اجرای برنامه شما را کند
می کند. بنابراین اگر می دانید متغیر شما چه typeی خواهد بود، باید از آن type استفاده کنید. اما در اینجا مثالی از انعطاف پذیری نوع object آورده شده است.
object obj = "hello"
//declare object variable as a string
Console.WriteLine("Current value of obj: " + obj);
obj = 22;
//change it to an integer
Console.WriteLine("Current value of obj: " + obj);
obj = 'i';
//change it to a char
Console.WriteLine("Current value of obj: " + obj);
obj = "hello there"
//change it back to a string
Console.WriteLine("Current value of obj: " + obj);
همه خطوط بدون هیچ مشکلی کامپایل می شوند.
دسته Chars :
دو نوع داده char عبارتند از char و string.شما یک char را در سی شارپ با احاطه کردن آن با نقل قول های تکی (' ') نشان می دهید. string آرایه ای از charها است.
یک char یک کاراکترliteral
یونیکد است، اما میتواند یک دنبالهhexadecimal
، یک کاراکتر unicode نیز باشد.
char ch = 'x'; //Unicode literal character
char hexChar = '\xF'; //hexadecimal number
char unicodeChar = '\u0058'; //Unicode character
char space = (char)32; //type casted from an integer
string str = "hello world" //example of a string
اما string مجموعه ای از charها است که در کنار هم قرار گرفته اند، که معمولاً به معنای تشکیل کلمات، جملات و غیره است.
در حالی که ضروری نیست، بسیار مهم است که بدانید در حین نوشتن کدتان چه چیزی در حافظه میگذرد، چه با رشتهها یا ساختارهای داده یا چیز دیگری باشد. این به رفع اشکالات نرمافزاری یا تشخیص نشت حافظه یا مشکلات عملکرد کمک میکند. بهترین مقایسه این است که بدانید زیر کاپوت وسیله نقلیه شما چه می گذرد. اگرچه دانستن آن حیاتی نیست، اما مفید است.
فرض کنید ما یک رشته جدید ایجاد می کنیم، سپس آن را اصلاح می کنیم و توضیح می دهیم که در تمام این مدت در حافظه چه اتفاقی می افتد.
وقتی رشته ای ایجاد می کنید، تغییر ناپذیر(immutable) است. یعنی فقط خواندنی(read-only) است. وقتی چیزی تغییرناپذیر یا فقط خواندنی است، به این معنی است که نمی توان آن را در زمان بعدی تغییر داد.(لطفا اشتباه برداشت نکنید شما می توانید رشته را در طول برنامه خود اصلاح کنید ما در حال بررسی اتفاقاتی هستیم که در حافظه و پشت صحنه برنامه ما اتفاق می افتد )
چرا رشته ها تغییر ناپذیر هستند ؟
در سی شارپ، CLR (Common Language Runtime) مسئول تعیین محل ذخیره رشته ها است. گفتیم که رشته آرایه ای از کاراکترها است. CLR یک آرایه را برای ذخیره رشته ها پیاده سازی می کند. آرایه ها یک ساختار داده با اندازه ثابت هستند، به این معنی که نمی توان آنها را به صورت پویا افزایش یا کاهش داد. هنگامی که به یک آرایه یک اندازه اختصاص داده می شود، اندازه آن قابل تغییر نیست. برای بزرگتر کردن یک آرایه، داده ها باید کپی و در یک آرایه جدید کلون شوند، که توسط CLR در یک بلوک جدید از حافظه قرار می گیرد. اگر یک رشته را ویرایش کنید، در واقع آن رشته را تغییر نمی دهید. بلکه CLR در حال ایجاد یک مرجع حافظه جدید برای رشته اصلاح شده است و رشته اصلی از طریق جمع آوری زباله(garbage collection) از حافظه حذف می شود.
پس وقتی یک رشته را تغییر می دهید، در واقع فقط یک شی جدید در حافظه ایجاد می کنید.
مزایای تغییر ناپذیری یا immutable بودن رشته ها چیست ؟
چرا باید از رشته های تغییرناپذیر استفاده کنید؟ یکی از مزیت ها این است که آنها thread safe هستند. اگر با یک multi threaded system کار می کنید، خطر deadlock یا مشکلات concurrency وجود نخواهد داشت، زیرا وقتی یک رشته را تغییر می دهید، در واقع فقط یک شی جدید در حافظه ایجاد می کنید. مزیت دیگر این است که نگران تغییر تصادفی آنها نخواهید بود. شما نیازی به انجام اقدامات ایمنی اضافی (به عنوان مثال یک کپی شی دفاعی) ندارید که ممکن است لازم باشد با یک شیء قابل تغییر انجام دهید.
معایب تغییر ناپذیری یا immutable بودن رشته ها چیست ؟
مسئله اصلی این است که تغییر مداوم رشته ها می تواند منجر به مشکلات عملکرد شود.
از آنجایی که رشته تغییرناپذیر است، آنچه در حافظه اتفاق میافتد این است که با هر بار اصلاح و تغییر یک رشته CLR فضای جدیدی را در حافظه اختصاص میدهد و یک متغیر جدید را ذخیره میکند، و هر بار بلوکهای بزرگتری برای ذخیره دادههای بیشتر ایجاد میکند.
اگر این کار را هزار، ده هزار یا یک میلیون بار انجام دهیم چه می شود؟ این امر مستلزم تخصیص مقدار زیادی از حافظه توسط CLR و مقدار زیادی کار برای جمعآوری زباله است. با همه این اتفاقات، به احتمال زیاد شاهد کاهش عملکرد خواهید بود. اگر در چنین سناریویی قرار گرفتید، ممکن است یک شیء قابل تغییر همان چیزی باشد که به آن نیاز دارید. یک پیشنهاد یک StringBuilder object است.
دسته bool
برای انجام عملیات منطقی با مقادیر از نوع bool، از عملگرهای منطقی Boolean استفاده کنید. نوع bool نوع نتیجه عملگرهای مقایسه و برابری است.
شما می توانید از لیترال true و false برای مقداردهی اولیه یک متغیر bool استفاده کنید.
مقدار پیش فرض نوع bool false است.
bool check = true;
Console.WriteLine(check ? "Checked" : "Not checked"); // output: Checked
Console.WriteLine(false ? "Checked" : "Not checked"); // output: Not checked
هنگام مقایسه دو مقدار با استفاده از عملگرهای مقایسه یا برابری، مقداری از نوع bool را دریافت خواهید کرد.
قراردادهای نامگذاری دات نت استانداردهایی هستند که چگونه نام گذاری متغیرها، متدها، کلاس ها و سایر عناصر را مشخص می کند.
سه اصطلاح زیر برای اعلام استانداردهای نامگذاری سی شارپ و دات نت استفاده می شود.
پس از اعلان یک متغیر، می توانید با استفاده از عملگر انتساب (=)، یک مقدار به آن اختصاص دهید، مانند این:
int age;
age = 18;
و می توانید هر دو مرحله را با استفاده از یک عبارت انجام دهید:
int age = 18;
سی شارپ یک زبان type-safe است. این بدان معنی است که کامپایلر اطمینان حاصل می کند که متغیر همیشه مقداری از نوع اعلام شده را ذخیره می کند.
در مثال بالا، متغیر age همیشه یک عدد صحیح را ذخیره می کند. اگر رشته ای به آن اختصاص دهید، کامپایلر با خطا مواجه می شود.
برای نمایش متغیر age در console ، از متد Console.WriteLine به صورت زیر استفاده می کنید:
int age = 18;
Console.WriteLine(age);
برای جاسازی متغیر age در یک رشته و نمایش آن، از عبارت زیر استفاده می کنید:
Console.WriteLine($"The age is {age}");
در این statement:
وقتی کامپایلر رشته ای را با پیشوند $ می بیند، تمام متغیرهای درون {} را با مقادیر متناظرشان جایگزین می کند.
برای اعلان چندین متغیر، می توانید از چند عبارت یا statement استفاده کنید:
double weight = 90.1;
double height = 1.90;
اگر متغیرها دارای یک نوع هستند، می توانید آنها را در یک عبارت اعلام کنید و از کاما (,) برای جدا کردن دو متغیر مانند زیر استفاده کنید:
double weight = 90.1,
height = 1.90;
Console.WriteLine($"The weight is {weight}kg and height is {height}m");
bmi = weight / (height * height);
Console.WriteLine($"BMI: {bmi:0.#}");
به آخرین خط از قطعه کد بالا توجه داشته باشید. این نحو مقدار BMI را فرمت دهی می کند که یک رقم بعد از نقطه اعشار نشان داده می شود:
{ bmi: 0.#}
اگر می خواهید عددی را با ارقام بیشتری بعد از نقطه اعشار قالب بندی کنید، می توانید تعداد بیشتری از نماد # اضافه کنید. هر نماد # نشان دهنده یک عدد است.
از کلمه کلیدی C# var برای اعلام متغیرهای implicit-typed استفاده کنید.
به عنوان مثال:
string txt = "Welcom to C#"
در این مثال، ما از نوع string برای متغیر txt و یک رشته لیترال به عنوان مقدار اولیه استفاده می کنیم. txt یک متغیر explicit-typed است.
با این حال، از مقدار "Welcom to C#"، کامپایلر می تواند متغیر را به عنوان رشته استنباط کند. بنابراین explicit-typed زاید است.
برای جلوگیری از این افزونگی، میتوانید از کلمه کلیدی var به جای نوع صریح در ابتدای اعلان متغیر مانند زیر استفاده کنید:
var txt = "Welcom to c#"
در این مثال، txt یک متغیر implicit-typed است.
کلمه کلیدی var نوع خاصی از متغیر را نشان نمی دهد. این مختصر نحوی برای هر نوع است که کامپایلر
می تواند از مقداردهی اولیه یک اعلان متغیر استنباط کند.
هنگامی که کامپایلر بتواند نوع متغیر را استنباط کند، ثابت و غیر قابل تغییر است. به عنوان مثال، شما نمی توانید یک عدد صحیح به متغیر txt مانند زیر اختصاص دهید:
var txt = "Welcom to c#"
txt= 20; // error
سی شارپ فقط به شما امکان می دهد از کلمه کلیدی var با متغیری که شامل مقداردهی اولیه است استفاده کنید. مورد زیر منجر به خطا می شود:
var txt;
از کلمه کلیدی var برای متغیری با مقداردهی اولیه استفاده کنید که کامپایلر می تواند یک type را از آن استنتاج کند.
مقادیر حداقل و حداکثر :
هر نوع عدد Integer دارای ثابت های MinValue و MaxValue است که حداقل و حداکثر نوع را ارائه می دهد. برای دسترسی به این مقادیر، از عملگر نقطه (.) استفاده می کنید. مثلا:
Console.WriteLine($"int range: ({int.MinValue},{int.MaxValue})");
مقایسه دو عدد شناور :
اگر بخواهید دو عدد شناور را با هم مقایسه کنید، ممکن است رفتار غیرمنتظرهای ایجاد شود.
bool result = 0.3 == 0.1 + 0.1 + 01;
Console.WriteLine(result); // false
دلیل آن این است که عبارت مقداری را برمی گرداند که تقریباً برابر با 0.3 است نه دقیقا خود 0.3
Console.WriteLine(0.1 + 0.1 + 0.1); // output : 0.30000000000000004
افزایش خوانایی اعداد در کد :
اگر یک عدد(چه در دسته Integers و چه در دسته Floating Points) بزرگ است، می توانید از جداکننده رقم (_) برای خوانایی بیشتر استفاده کنید.مثلا:
int prize = 1_000_000;
برای ایجاد یک رشته با طول صفر :
از String.Empty مانند زیر استفاده می کنید:
string txt= String.Empty;
که معادل است با :
string txt= ""
بدست آوردن طول یک رشته :
string txt = "welcom to c#"
Console.WriteLine(txt.Length);
الحاق دو رشته :
string txt = "welcom to" + " c#"
Console.WriteLine(txt);
برای الحاق یک رشته به رشته دیگر، می توانید از عملگر += نیز استفاده کنید. مثلا:
string txt = "welcom to"
txt+= " C#"
Console.WriteLine(txt);
دسترسی به یک کارکتر منفرد در رشته :
سی شارپ یک رشته را به عنوان مجموعه ای از کاراکترهای فقط خواندنی ذخیره می کند. برای دسترسی به یک کاراکتر منفرد در یک رشته، از نماد براکت [] با یک شاخص استفاده میکنید:
string txt = "welcom to c#"
Console.WriteLine(txt[0]); // w
از آنجا که یک رشته تغییر ناپذیر است، شما فقط می توانید کاراکترهای جداگانه را از آن بخوانید.
مثال زیر منجر به یک خطای کامپایل می شود زیرا تلاش می کند اولین کاراکتر یک رشته را تغییر دهد:
string txt = "welcom to c#"
txt[0] = 'A';
ـEscape sequences :
یک literal string میتواند شامل کاراکترهای ویژه مانند tabs, newlines، ... با استفاده از بک اسلش (\) باشد. به آنها Escape sequences می گویند. مثلا:
string txt = "hello\World"
Console.WriteLine(txt); //output : hello world
ـVerbatim string:
اگر رشته ای دارای بک اسلش باشد، می توانید با استفاده از بک اسلش از آنها فرار کنید. اما بک اسلش های دوتایی خوانایی رشته را دشوار می کند.
برای رفع این مشکل، میتوانید یک رشته لیترال را با پیشوند علامت @ به یک رشته کلمه به کلمه تبدیل کنید. مثلا:
string path = @"C:\programsFiles\"
Console.WriteLine(path); //output : C:\programsFiles\
ـInterpolated string :
فرض کنید یک متغیر به name دارید:
string name = "reza"
و شما می خواهید متغیر را در یک رشته لیترال جاسازی کنید.
برای انجام این کار، پیشوند رشته لیترال را کاراکتر $ قرار داده و متغیر را در داخل {} قرار دهید:
string name = "reza"
string txt= $"Hi{name}!"
Console.WriteLine(txt); //output : Hello Joe!
یک رشته تحت لیترال با پیشوند $ یک رشته درون یابی(Interpolated string) است.هنگام مواجهه با پیشوند $، کامپایلر متغیر {name} را با مقدار آن جایگزین می کند. این ویژگی درون یابی رشته ای نامیده می شود.
هنگام مواجهه با پیشوند $، کامپایلر متغیر {name} را با مقدار آن جایگزین می کند. این ویژگی درون یابی رشته ای نامیده می شود.
بیشتر بخوانید : دوره آموزشی #C - قسمت سوم - CONTROL FLOW
بیشتر بخوانید : نقشه راه توسعه دهندگان Asp.NET Core