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

آموزش سی شارپ – عملگرها

آموزش سی شارپ - عملگرها
آموزش سی شارپ - عملگرها

عملگرها در سی شارپ

در این بخش از آموزش برنامه نویسی به زبان سی شارپ قصد بررسی عملگرهای برنامه نویسی زبان سی شارپ را داریم. عملگرها در زبان‌های برنامه نویسی از جایگاه ویژه‌ای برخوردارند که این موضوع از هیچ برنامه نویسی پوشیده نیست.

 

عملگرها در سی شارپ

حتما قبل از بررسی عملگرها در سی شارپ نوشته ی مطالب قبلی این دوره‌ی آموزشی را با هشتگ #دوره آموزشی_سی_شارپ در سایت ما را مطالعه کنید.

تبدیل یک نوع‌های داده‌ای به نوع دیگر

در برنامه‌ نویسی بارها مواردی به‌وجود می‌آید که یک نوع از یک متغیر را به نوع دیگری اختصاص دهید.

در مواردی که عملیات ریاضی انجام می‌دهید، نتیجه‌ی محاسبات از جنس متغیر شما خواهد بود.

برای مثال هنگامی‌که دو int را بر هم تقسیم می‌کنید، نتیجه از جنس int خواهد بود.

هنگامی‌که دو نوع سازگار با هم ترکیب می‌شوند، مقدار سمت راست به‌صورت اتوماتیک به نوع متغیر سمت چپ تبدیل می‌شود.

بنابراین در برنامه بالا، مقدار i ابتدا به double تبدیل شده و سپس به b اختصاص می‌یابد.

int i = 180;
double b;
b = i; // assing an int to a double

به‌ علت سخت‌گیری سی‌شارپ در بررسی نوع داده‌ها، هر نوع داده‌ای برای تبدیل شدن به نوع دیگر سازگار نیست.

به‌صورت اتوماتیک convert نمی‌شود که در این موارد برای کانورت می‌توان از cast کردن استفاده کرد.

برای تبدیل نوع داده به نوع دیگر و کانورت کردن، دو روش موجود است:

  • Implicit
  • Explicit

در روش implicit تبدیل نوع به‌صورت اتوماتیک اتفاق می‌افتد به‌شرطی‌ که:

هر دو نوع داده با هم سازگار بشوند. بازه و محدوده‌ی نوع مقصد بزرگ‌تر از بازه و محدوده‌ی نوع مبدا است. هنگامی‌که این دو شرط برقرار هستند تبدیل نوع به‌صورت اتوماتیک (implicit) انجام می‌شود و به اصطلاح یک widening conversion اتفاق می‌افتد. به‌عنوان مثال نوع int محدوده و بازه‌ی کافی برای نگه‌داری نوع byte را در خود دارد. هم‌چنین int و byte دو نوع سازگار هستند. بنابراین یک کانورت به روش implicit می‌تواند اتفاق افتد.

به مثال زیر توجه کنید:

int i = 300;
byte b = 255;
i = b; // assing a byte to an int

در این مثال یک implicit conversion اتفاق می‌افتد زیرا هر دو شرط برای این تبدیل نوع برقرار است.

اگرچه برای اختصاص دادن byte به int کانورت به‌صورت implicit اتفاق می‌فتد اما برای اختصاص دادن int به byte این اتفاق نمی‌افتد.

به اصطلاح widening conversionای در کار نیست زیرا یکی از آن دو شرط برای implicit conversion نقض شده است. (بازه و محدوده‌ی نوع مقصد باید بزرگ‌تر از بازه و محدوده‌ی نوع مبدا بشود)

به مثال زیر که نادرست است و اجرا نمی‌شود توجه کنید:

int i = 150;
byte b;

b = i; // Illegal!!!

البته با یک تغییر کوچک برنامه بالا قابل اجرا خواهد بود که در ادامه به شرح آن می‌پردازیم.

اگر دقت نمایید هنگام اجرای برنامه بالا این پیغام خطا را دریافت می‌کنید:

Connot implicitly convert type ‘int’ to ‘byte’. An explicit conversion exists (are you missing a cast?)

برای نوع داده‌هایی که با هم سازگاری ندارند و به ‌صورت implicit نمی‌توانند کانورت شوند باید از از روش explicit و cast کردن استفاده کرد.

در cast کردن ما به کامپایلر دستور می‌دهیم که نوع یک متغیر را آن‌طور و به آن‌چه که می‌خواهیم تبدیل کند (روش explicit).

فرم کلی cast کردن به شکل زیر است:

(target-type) expression

در این‌جا، target-type مشخص کننده‌ی نوعی است که شما خواسته‌اید expression به آن تبدیل شود.

به‌عنوان مثال:

double x, y;

اگر شما بخواهید که حاصل x / y از جنس int باشد می‌توانید بنویسید:

(int)(x / y);

همان‌طور که می‌دانید x و y از جنس double هستند اما از طریق cast کردن حاصل آن‌ها تبدیل به int شده است. به این مثال توجه کنید:

double x, y;
x = 25.3;
y = 5.1;
int result = (int)(x / y);

در برنامه بالا x و y که هردو از جنس double هستند بر هم تقسیم شده‌اند. حاصل این تقسیم مسلماً از جنس double خواهد بود اما ما از طریق cast کردن آن را به int تبدیل کرده‌ایم. پرانتز‌های اطراف x و y ضروری هستند زیرا در صورت نبود آن‌ها تنها x به int تبدیل می‌شود. در cast کردن اگر نوع متغیر مقصد کوچک‌تر از مبدا است ممکن است بخشی از اطلاعات از بین برود. هم‌چنین هنگام cast کردن مقادیر اعشاری به عدد صحیح قسمت اعشاری آن‌ها از بین می‌رود. برای مثال هنگام cast کردن مقدار ۱٫۲۳ به عدد صحیح نتیجه ۱ خواهد بود. هم‌چنین هنگامی‌که قصد دارید نوع int را در نوع byte قرار دهید مقداری از اطلاعات ممکن از از بین برود.

چراکه نهایت مقداری که byte می‌تواند ذخیره کند عدد ۲۵۵ است:

int anOkayInt = 345;
byte aBadByte = (byte)anOkayInt;

خروجی این برنامه عدد ۸۹ است. اگر قصد داشته باشید عدد ۲۵۶ را از طریق cast کردن در byte ذخیره کنید، عددی که ذخیره می‌شود صفر است. اگر ۲۵۷ را در byte ذخیره کنید، عدد ۱ ذخیره می‌شود و همین‌طور که می‌بینید ذخیره‌ی عدد ۳۴۵ در byte موجب شده تا عدد ۸۹ در آن قرار گیرد که دقیقاً معادل تفریق ۳۴۵ و ۲۵۶ است. اگر (x / y) به int تبدیل شود. قسمت اعشاری نتیجه‌ی تقسیم از بین می‌رود. اگر عدد صحیح ۲۵۵ را به byte اختصاص دهیم و به این علت که byte توانایی نگه‌داری این مقدار را دارد، هیچ اطلاعاتی از بین نمی‌رود. اما با این حال به cast کردن نیاز است چراکه به‌صورت implicit نمی‌توان int را به byte کانورت کرد. اگر ۲۵۷ را به byte اختصاص دهیم موجب از بین رفتن اطلاعات می‌شود. اگر متغیری که قرار است مقداری در آن ریخته شود، گنجایش کافی برای نگه‌داری از آن را داشته باشد هیچ اطلاعاتی از بین نخواهد رفت. در غیر این‌صورت بخشی از اطلاعات از بین می‌رود.

 

عملگرهای منطقی (Logical Operators)

در عمل‌گرهای منطقی ما با عمل‌وندهایی از جنس بولین سروکار داریم که در نهایت نتیجه از جنس bool خواهد بود. عمل‌گرهای منطقی شامل AND و OR و XOR و NOT هستند که به‌ترتیب با علامت‌های & و | و ^ و ! مشخص می‌‌شوند.

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

bool p, q;
p = true;
q = false;
if (p & q) Console.WriteLine("this won't execute");
if (!(p & q)) Console.WriteLine("!(p & q) is true");
if (p | q) Console.WriteLine("p | q is true");
if (p ^ q) Console.WriteLine("p ^ q is true");

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

عملگر Implication

یکی دیگر از عمل‌گرهای منطقی عمل‌گر implication است. این عمل‌گر نیز پاسخی از نوع بولین دارد. در این عمل‌گر تنها زمانی که عمل‌وند سمت چپ برابر با true و عمل‌وند سمت راست برابر با false است. پاسخ برابر با false می‌شود.

نتیجه‌ای که از این عمل‌گر گرفته می‌شود این است: اگر مقدار p برابر با true است آن‌گاه مقدار q نیز باید true باشد.

عملیات implication از طریق الگوی زیر انجام می‌شود:

!p | q

 

عملگرهای منطقی Short-Circuit یا اتصال کوتاه

سی‌شارپ ورژن مخصوصی برای AND و OR تدارک دیده که به Short-Circuit یا اتصال کوتاه معروف هستند. استفاده از Short-Circuit موجب می‌شود کد بهینه‌تر و پر سرعت‌تری داشته باشید. همان‌طور که می‌دانید در AND اگر عمل‌وند اول False باشد آن‌گاه جواب False است و در OR اگر عمل‌وند اول True باشد پاسخ True خواهد بود. کاری که Short-Circuit انجام می‌دهد این است که در این موارد، بقیه‌ی حالت‌ها را ارزیابی نکرده و مستقیماً جواب نهایی را می‌دهد. در صورتی‌که در AND و OR معمولی همه‌ی حالت‌ها بررسی می‌شوند. علامت Short-Circuit AND به‌صورت && و علامت Short-Circuit OR به‌صورت || است که هم‌چنین با عناوین Conditional AND و Conditional OR نیز شناخته می‌شوند.

به نمونه‌ی زیر توجه کنید:

int i;
bool someCondition = false;

i = 0;

if (someCondition & (++i < 100))
   Console.WriteLine("this won't be displayed");
Console.WriteLine("if statement executed: " + i); // displays 1

if (someCondition && (++i < 100))
   Console.WriteLine("this won't be displayed");
Console.WriteLine("if statement executed: " + i); // still 1 !!

در این برنامه متغیر iدر ابتدا برابر صفر است. در دستور شرطی if به‌دلیل وجود عمل‌گر AND معمولی، هردو عمل‌وند آن ارزیابی می‌شوند بنابراین i یک واحد افزایش می‌یابد. در دستور if بعدی به‌دلیل وجود Short-Circuit AND عمل‌وند اول ارزیابی می‌شود. به‌دلیل False بودن، دیگر عمل‌وند دوم ارزیابی نشده و i افزایش پیدا نمی‌کند.

 

عملگرهای بیتی (The Bitwise Operators)

عمل‌گرهای بیتی مستقیماً روی بیت‌های عمل‌وندشان کار می‌کنند و تنها برای مقادیر صحیح تعریف شده‌اند. نمی‌توانند برای نوع‌های bool، float و double به‌کار گرفته شوند. این عمل‌گرها برای اعمالی چون برنامه‌نویسی در سطوح پایین سیستم به‌کار می‌روند. عمل‌گرهای بیتی شامل AND و OR و XOR و NOT هستند که به ‌ترتیب با نشانه‌های & و | و ^ و ~ نشان داده می‌شوند. تفاوت عمل‌گرهای بیتی با عمل‌گرهای منطقی در این است که عمل‌گرهای بیتی مستقیماً روی تک تک بیت‌های عمل‌وندشان کار می‌کنند.

به نمونه ی زیر توجه کنید:

int i = 25; // Bits of i: 00011001
int j = 30; // Bits of j: 00011110

int resutl = i & j; // (00011001) & (00011110) produce 00011000

Console.WriteLine("First Number: {0}\nSecond Number: {1}", i, j);
Console.WriteLine();
Console.WriteLine("Result of AND Operation: " + resutl); // Result is 00011000 that means 24

resutl = i | j; // (00011001) | (00011110) produce 00011111
Console.WriteLine("Result of OR Operation: " + resutl); // Result is 00011111 that means 31

resutl = i ^ j; // (00011001) | (00011110) produce 00000111
Console.WriteLine("Result of XOR Operation: " + resutl); // Result is 00000111 that means 7

resutl = ~i; // ~(00011001) produces 11100110
Console.WriteLine("Result of NOT Operation: " + resutl); // Result is 11100110 that means -26

معادل صفر و یک متغیرهای i و j در قسمت کامنت‌ها نوشته شده است. این صفر و یک‌ها طبق جدول با یکدیگر AND و OR و XOR و NOT می‌شوند و مقادیر جدیدی را تولید می‌کنند. دو عمل‌گر بیتی دیگر با نام‌های Shift left و Shift right وجود دارند که به ‌ترتیب با نمادهای >> و << نشان داده می‌شوند. توسط این دو عمل‌گر می‌توانید بیت‌ها به سمت چپ یا راست انتقال دهید.

فرم کلی این دو عمل‌گر به‌شکل زیر است:

value << num-bits

value >> num-bits

در این‌جا value عددی است که قصد داریم بیت‌های آن‌ها را به تعداد num-bits به چپ یا راست شیفت دهیم.

به نمونه‌ی زیر دقت کنید:

int result = 2 << 1; // 0010 becomes 0100 (Left shift)

در Shift right/Shift left بیت‌ها از مکان فعلی خودشان به‌اندازه یک بیت به چپ/راست انتقال می‌یابند. در مثال بالا بیت‌های عدد ۲ را به‌اندازه یک بیت به سمت چپ انتقال داده‌ایم که موجب شده است عدد ۲ به عدد ۴ تبدیل شود.

int result = 8 >> 1; // 1000 becomes 0100 (Right shift)

در این‌جا بیت‌های عدد ۸ را به‌اندازه یک بیت به سمت راست انتقال داده‌ایم که موجب شده است عدد ۸ به ۴ تبدیل شود. بنابراین نتیجه می‌گیریم که یه بیت شیفت به چپ مقدار را دو برابر و یک بیت شیفت به راست مقدار را نصف می‌کند. در پرو‌ژهایی با مقیاس بزرگ از این روش (به‌جای استفاده از ضرب و تقسیم معمولی) برای بالا بردن سرعت برنامه استفاده می‌کنند.

 

نظرات خود را در ارتباط با “عملگرها در سی شارپ” برای ما ارسال کنید.

برای استفاده از تمامی جلسات از هشتگ #دوره آموزشی_سی_شارپ در سایت ما استفاده کنید.

منتظر جلسه ی بعدی دوره آموزشی سی شارپ بمانید.

برای امتیاز به این نوشته کلیک کنید!
[کل: 1 میانگین: 5]