نحوه راه اندازی گوشی های هوشمند و رایانه های شخصی پرتال اطلاعاتی

اپراتورها شارپ هستند. عبارات شرطی

اخرین بروزرسانی: 19.06.2017

C# از بیشتر عملیاتی استفاده می کند که در سایر زبان های برنامه نویسی استفاده می شود. عملیات نشان دهنده اقدامات خاصی بر روی عملوندهایی است که در عملیات شرکت می کنند. عملوند می تواند یک متغیر یا مقداری (مثلاً یک عدد) باشد. عملیات ها می توانند تکی (انجام شده بر روی یک عملوند)، باینری - روی دو عملوند، و سه تایی - بر روی سه عملوند انجام شوند. بیایید همه انواع عملیات را در نظر بگیریم.

عملیات حسابی باینری:

    عملیات جمع دو عدد:

    Int x = 10; int z = x + 12; // 22

    عمل تفریق دو عدد:

    Int x = 10; int z = x - 6; // 4

    عمل ضرب دو عدد:

    Int x = 10; int z = x * 5; // 50

    عمل تقسیم دو عدد:

    Int x = 10; int z = x / 5; // 2 دو برابر a = 10; دو برابر b = 3; دو برابر c = a / b; // 3.33333333

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

    z دو برابر = 10/4; // نتیجه 2 است

    با وجود اینکه نتیجه عملیات در نهایت در یک متغیر قرار می گیرد از نوع دوبلکه به شما امکان ذخیره می دهد قسمت کسری، اما خود عملیات شامل دو حرف است که به طور پیش فرض به عنوان اشیاء int یعنی اعداد صحیح در نظر گرفته می شوند و نتیجه مانند یک عدد صحیح خواهد بود.

    برای برون رفت از این وضعیت، لازم است لفظ ها یا متغیرهای شرکت کننده در عملیات دقیقاً به صورت دو یا شناور تعریف شوند:

    دابل z = 10.0 / 4.0; // نتیجه 2.5 است

    عملیات گرفتن باقی مانده از تقسیم عدد صحیحدو عدد:

    دو برابر x = 10.0; z double = x% 4.0; // نتیجه 2 است

یک عدد هم هست عملیات واحد، که در آن یک عملوند شرکت می کند:

    عملیات افزایشی

    افزایش را می توان پیشوند کرد: ++ x - ابتدا مقدار متغیر x 1 افزایش می یابد و سپس مقدار آن به عنوان نتیجه عملیات برگردانده می شود.

    و همچنین یک افزایش پسوند وجود دارد: x ++ - ابتدا مقدار متغیر x به عنوان نتیجه عملیات برگردانده می شود و سپس 1 به آن اضافه می شود.

int x1 = 5; int z1 = ++ x1; // z1 = 6; x1 = 6 Console.WriteLine ($ "(x1) - (z1)"); int x2 = 5; int z2 = x2 ++; // z2 = 5; x2 = 6 Console.WriteLine ($ "(x2) - (z2)");

عملیات کاهش یا کاهش یک مقدار. همچنین یک پیشوند کاهش (--x) و یک پسوند (x--) وجود دارد.

Int x1 = 5; int z1 = --x1; // z1 = 4; x1 = 4 Console.WriteLine ($ "(x1) - (z1)"); int x2 = 5; int z2 = x2--; // z2 = 5; x2 = 4 Console.WriteLine ($ "(x2) - (z2)");

هنگام انجام چندین عملیات حسابی به طور همزمان، ترتیب انجام آنها را در نظر بگیرید. اولویت عملیات از بالاترین به پایین ترین:

    افزایش، کاهش

    ضرب، تقسیم، به دست آوردن باقی مانده

    جمع، تفریق

از براکت ها برای تغییر ترتیب عملیات استفاده می شود.

مجموعه ای از عملیات را در نظر بگیرید:

Int a = 3; int b = 5; int c = 40; int d = c --- b * a; // a = 3 b = 5 c = 39 d = 25 Console.WriteLine ($ "a = (a) b = (b) c = (c) d = (d)");

در اینجا با سه عمل کاهش، تفریق و ضرب سروکار داریم. ابتدا c کاهش می یابد، سپس b * a ضرب و سپس کم می شود. یعنی در واقع مجموعه عملیات به این صورت بود:

Int d = (c -) - (b * a);

اما با استفاده از پرانتز می‌توانیم ترتیب عملیات را مثلاً به صورت زیر تغییر دهیم:

Int a = 3; int b = 5; int c = 40; int d = (c - (- b)) * a; // a = 3 b = 4 c = 40 d = 108 Console.WriteLine ($ "a = (a) b = (b) c = (c) d = (d)");

انجمن اپراتور

همانطور که در بالا ذکر شد، عملیات ضرب و تقسیم دارای اولویت یکسانی هستند، اما نتیجه در عبارت:

Int x = 10/5 * 2;

آیا باید این عبارت را به (10/5) * 2 تفسیر کنیم یا 10 / (5 * 2)؟ در واقع، بسته به تفسیر، نتایج متفاوتی خواهیم گرفت.

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

    عملگرهای انجمنی چپ که از چپ به راست اجرا می شوند

    عملگرهای ارتباطی راست که از راست به چپ اجرا می کنند

همه چيز عملگرهای حسابی(به جز پیشوند افزایش و کاهش) چپ انجمنی هستند، یعنی از چپ به راست انجام می شوند. بنابراین، عبارت 10/5 * 2 باید به صورت (10/5) * 2 تفسیر شود، یعنی نتیجه 4 خواهد بود.

عملگرهای رابطه و عملگرهای منطقی

در نماد عملگر رابطهو عملگر منطقیمدت، اصطلاح ارتباطبه معنای رابطه ای است که می تواند بین دو معنی و اصطلاح وجود داشته باشد منطقی- رابطه بین مقادیر منطقی "درست" و "نادرست". و از آنجایی که عملگرهای رابطه ای نتایج درست یا نادرست می دهند، اغلب همراه با عملگرهای منطقی استفاده می شوند. به همین دلیل است که آنها را با هم در نظر می گیرند.

عملگرهای رابطه ای زیر هستند:

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

نتیجه اجرای یک عملگر رابطه یا یک عملگر منطقی یک مقدار بولی از نوع bool است.

به طور کلی، اشیاء را می توان با استفاده از عملگرهای رابطه ای == و! = برای برابری یا نابرابری مقایسه کرد. عملگرهای مقایسه، =، فقط می توانند برای انواع داده ای اعمال شوند که از یک رابطه سفارشی پشتیبانی می کنند. بنابراین، عملگرهای رابطه ای را می توان برای تمام انواع داده های عددی اعمال کرد. اما مقادیر bool را فقط می توان برای برابری یا نابرابری مقایسه کرد، زیرا مقادیر درست و نادرست مرتب نمی شوند. به عنوان مثال، مقایسه true> false در C # بی معنی است.

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

استفاده از سیستم؛ با استفاده از System.Collections.Generic. با استفاده از System.Linq؛ با استفاده از System.Text. فضای نام ConsoleApplication1 (کلاس برنامه (خلأ ثابت اصلی (رشته آرگ) (d = 10 کوتاه، f = 12؛ bool var1 = درست، var2 = نادرست؛ if (df) Console.WriteLine ("d> f")؛ // مقایسه متغیرهای var1 و var2 if (var1 & var2) Console.WriteLine ("این متن نمایش داده نمی شود")؛ if (! (var1 & var2)) Console.WriteLine ("! (var1 & var2) = true")؛ اگر (var1 | var2) Console.WriteLine ("var1 | var2 = true")؛ if (var1 ^ var2) Console.WriteLine ("var1 ^ var2 = true")؛ Console.ReadLine ();)))

عملگرهای بولی در C# رایج ترین عملیات منطقی را انجام می دهند. با این وجود، تعدادی عملیات طبق قوانین منطق رسمی انجام می شود. این عملیات بولی را می توان با استفاده از عملگرهای بولی که در سی شارپ پشتیبانی می شوند، ساخت. بنابراین، C# چنین مجموعه ای از عملگرهای منطقی را ارائه می دهد که برای ساخت تقریباً هر عملیات منطقی، از جمله مفاهیم، ​​کافی است. پیامدیک عملیات باینری است که فقط در صورتی نادرست ارزیابی می شود که عملوند سمت چپ آن داشته باشد معنی واقعیو حق باطل است. (عملیات ضمنی منعکس کننده اصل زیر است: صدق نمی تواند به معنای نادرست باشد.)

عملیات ضمنی را می توان بر اساس ترکیبی از عملگرهای منطقی ساخت! و |:

عملگرهای منطقی کوتاه شده

C # همچنین موارد خاصی را ارائه می دهد، کوتاه شده است، انواع عملگرهای منطقی AND و OR، طراحی شده برای به دست آوردن کد کارآمدتر. اجازه دهید در این مورد توضیح دهیم نمونه های زیرعملیات منطقی اگر عملوند اول یک عملیات AND منطقی نادرست باشد، بدون توجه به مقدار عملوند دوم، نتیجه آن نادرست خواهد بود. اگر عملوند اول یک عملیات OR منطقی دارای مقدار واقعی (true) باشد، نتیجه آن بدون توجه به مقدار عملوند دوم، مقدار واقعی خواهد داشت. با توجه به اینکه مقدار عملوند دوم در این عملیات نیازی به محاسبه ندارد. باعث صرفه جویی در زمان و بهبود کارایی کد می شود.

یک عملیات AND منطقی کوتاه شده با استفاده از آن انجام می شود اپراتور &&و یک عملیات OR منطقی کوتاه شده با استفاده از اپراتور ||... این عملگرهای منطقی کوتاه شده با عملگرهای منطقی معمول & و | مطابقت دارند. تنها تفاوت بین یک عملگر منطقی کوتاه شده و یک عملگر معمولی این است که عملوند دوم آن فقط در صورت نیاز ارزیابی می شود.

هیچ تبدیل بولی ضمنی در C # وجود ندارد، حتی برای اعداد صحیح انواع حسابی... بنابراین، علامت گذاری در زبان C ++ کاملاً صحیح است:

بین المللیک1 = 7;
اگر (ک1) کنسول. WriteLine(" خوب!");

غیر قانونی در برنامه های C # در مرحله ترجمه، یک خطا رخ می دهد زیرا شرط محاسبه شده دارای نوع است بین المللی, و تبدیل ضمنی این نوع به تایپ بوولغایب.

در سی شارپ، قوانین سختگیرانه تری برای عملیات منطقی نیز اعمال می شود. بنابراین، ورودی اگر(ک1 && (ایکس> y)), درست در C ++، منجر به خطا در

برنامه های C # زیرا && فقط برای عملوندهای نوع تعریف شده است بوول, و در این عبارت یکی از عملوندها از نوع است بین المللی. در زبان C #، در این شرایط، باید از ورودی های زیر استفاده کنید:

اگر(ک1>0)
اگر((ک1>0) && (ایکس> y))

عملیات منطقی به دو دسته تقسیم می‌شوند: برخی بر روی مقادیر بولی عملوندها انجام می‌شوند، در حالی که برخی دیگر عملیات بولی را روی بیت‌های عملوند انجام می‌دهند. به همین دلیل، دو عملگر نفی واحد در C # وجود دارد - نفی منطقی، همانطور که توسط عملگر مشخص شده است، و نفی بیتی، همانطور که توسط عملگر ~ مشخص شده است. اولین مورد بر روی یک عملوند از نوع تعریف می شود بوول, دوم - روی یک عملوند از نوع عدد صحیح، که با نوع شروع می شود بین المللیو بالاتر (بین المللی, unint, طولانی, طولانی). نتیجه عمل در حالت دوم یک عملوند است که در آن هر بیت با مکمل خود جایگزین می شود. بیایید مثالی بزنیم:

/// < خلاصه>
/// عبارات بولی
/// خلاصه>
عمومیخالیمنطق() {
// عملیات نفی ~،!
bool b1, b2;
b1= 2*2 == 4;
b2= b1;
// b2 = ~ b1;
uint j1= 7, j2;
j2= ~ j1;
// j2= j1;
int j4= 7, j5;
j5= ~ j4;
Console.WriteLine ("uint j2= " + j2+ " int j5= " + j5)؛
} // منطق

در این قطعه، عباراتی که منجر به خطا می شوند، توضیح داده می شوند. در مورد اول، تلاش شد تا عملیات نفی بیتی برای عبارتی مانند اعمال شود بوول, در مرحله دوم، نفی منطقی برای داده های عدد صحیح اعمال شد. هر دو در C # غیرقانونی هستند. به تفاسیر مختلف نفی بیتی برای انواع اعداد صحیح بدون علامت و علامت توجه کنید. برای متغیرها j5 و j2 رشته بیتی که مقدار را تعریف می کند یکسان است، اما تفسیر متفاوتی دارد. نتیجه گیری مربوطه این است:

unintj2 = 4294967288
بین المللیj5 = -8.

عملیات منطقی باینری " && - مشروط و "و" || - OR مشروط فقط روی داده های نوع تعریف می شوند بوول. عملیات شرطی یا کوتاه نامیده می شود، زیرا محاسبه عملوند دوم به مقدار محاسبه شده از قبل عملوند اول بستگی دارد. ارزش عملیات منطقی شرطی در کارایی آنها از نظر زمان اجرا است. آنها اغلب به شما اجازه محاسبه می دهند بیان بولیمنطقی است، اما در آن عملوند دوم تعریف نشده است. بیایید به عنوان مثال مشکل کلاسیک جستجوی یک الگو در یک آرایه را در نظر بگیریم، زمانی که عنصری با مقدار مشخص (الگو) جستجو می‌شود. ممکن است چنین عنصری در آرایه وجود داشته باشد یا نباشد. در اینجا یک راه حل معمولی برای این مشکل به شکل ساده شده است، اما ماهیت موضوع را می رساند:

// مشروطو- &&
بین [] ar= { 1, 2, 3 };
جستجوی بین المللی= 7;
int i= 0;
در حالی که ((< ar.Length)&& (ar [i]!= جستجو کردن)){
من ++;
}
اگر من< ar.Length)Console.WriteLine ("نمونهیافت");
دیگرConsole.WriteLine ("نمونهنهیافت");

اگر مقدار متغیر جستجو کردن(الگو) با هیچ یک از مقادیر عناصر آرایه مطابقت ندارد ar, سپس آخرین بررسی شرط حلقه در حالی کهاگر مقدار اجرا شود من, برابر ar. طول. در این حالت، عملوند اول مقدار را دریافت می کند نادرست, و اگرچه عملوند دوم تعریف نشده است، حلقه به طور معمول خاتمه می یابد. عملوند دوم در تعریف نشده است آخرین بررسیزیرا شاخص یک عنصر در آرایه خارج از محدوده است (در C#، نمایه سازی عناصر از صفر شروع می شود).

سه باینری عملیات بیتی- "& - AND"، "| - OR "," ^ - XOR "به دو صورت استفاده می شود. آنها به عنوان انواع عدد صحیح بالا تعریف می شوند بین المللی, و بیش از انواع بولی. در حالت اول، آنها به عنوان عملیات بیتی و در حالت دوم، به عنوان عملیات منطقی معمولی استفاده می شوند. گاهی اوقات لازم است که هر دو عملوند در هر صورت محاسبه شوند، در این صورت نمی توان از این عملیات اجتناب کرد. در اینجا نمونه ای از استفاده از آنها برای اولین بار آورده شده است:

// عملیات بیتی منطقیو, یا, XOR(&,|,^)
int k2= 7, k3= 5, k4، k5، k6;
k4= k2& k3;
k5= k2 | k3;
k6= k2 ^k3;
Console.WriteLine ("k4= " + k4+ " k5= " + k5+ " k6= " + k6)؛

نتایج خروجی:

ک4 = 5 ک5 = 7 ک6 =2

در اینجا نمونه ای از جستجوی الگو با استفاده از AND منطقی آورده شده است: من= 0;

جستجو کردن= ar;
در حالی که ((< ar.Length)& (ar [i]!= جستجو)) i ++;
اگر من< ar.Length)Console.WriteLine ("نمونهیافت");
دیگری جConsole.WriteLine ("نمونهنهیافت");

این قطعه دارای الگوی جستجو در آرایه تضمینی است و قطعه با موفقیت اجرا می شود. در موارد مشابهی که آرایه حاوی عنصر نیست جستجو کردن, یک استثنا پرتاب خواهد شد. معنای معنی دار چنین رویه ای - ظاهر یک استثنا - ممکن است نشانه ای از خطا در داده ها باشد که نیاز به رسیدگی ویژه به موقعیت دارد.

فصل 10. عبارات و عملگرها

در این فصل، پایه و اساس هر زبان برنامه نویسی را بررسی خواهیم کرد – توانایی آن در انجام تکالیف و مقایسه با استفاده از عملگرها. ما خواهیم دید که چه عملگرهایی در C # هستند و اولویت آنها چقدر است، و سپس در دسته بندی های جداگانه عبارات برای انجام عملیات حسابی، تخصیص مقادیر و مقایسه عملوندها فرو می رویم.

اپراتورها

عملگر نمادی است که عملیاتی را که باید روی یک یا چند آرگومان انجام شود را نشان می دهد. وقتی دستور اجرا شد، نتیجه به دست می آید. سینتکس استفاده از عملگرها کمی با روش های فراخوانی متفاوت است و باید فرمت عبارات حاوی عملگرها را در سی شارپ مانند پشت دست خود بدانید. مانند بسیاری از زبان‌های دیگر، معناشناسی عملگرها در C# از قوانین و نشانه‌های آشنا از مدرسه پیروی می‌کند. اپراتورهای پایهدر C # شامل ضرب (*)، تقسیم (/)، جمع و یک واحد به علاوه (+)، تفریق و منهای یکنفره (-)، مدول (%) و تخصیص (=).

اپراتورها برای به دست آوردن یک مقدار جدید از مقادیر مورد استفاده استفاده می شوند. این مقادیر اولیه نامیده می شوند عملوندهانتیجه عملیات باید در حافظه ذخیره شود. گاهی اوقات در یک متغیر حاوی یکی از عملوندهای اصلی ذخیره می شود. اگر مقدار جدیدی در هنگام استفاده از اپراتور تعریف نشده یا ذخیره نشود، کامپایلر C# یک پیام خطا ایجاد می کند. کد زیر مقادیر را تغییر نمی دهد. کامپایلر یک پیام خطا صادر می کند زیرا یک عبارت حسابی که حداقل یک مقدار را تغییر نمی دهد معمولاً یک خطا در نظر گرفته می شود.

کلاس NoResultApp

{

خلأ استاتیک عمومی اصلی ()

{

int i; int j;

i + j; // خطا به دلیل اینکه نتیجه به چیزی اختصاص داده نشده است. )>

اکثر اپراتورها فقط با انواع داده های عددی مانند بایت، کوتاه، بلند، عدد صحیح، تک، دوتاییو اعشاری.یک استثنا عملگرهای مقایسه (== و! =) هستند. همچنین در C# می توانید از عملگرهای + و - برای کلاس استفاده کنید رشتهو حتی از عملگرهای افزایشی (++) و (-) برای ساختارهای زبان غیرمعمول مانند delegates استفاده کنید. در مورد دومی در فصل 14 صحبت خواهم کرد.

سابقه اپراتور

هنگامی که چندین دستور در یک عبارت وجود دارد، کامپایلر باید ترتیب اجرای آنها را تعیین کند. در این حالت کامپایلر توسط قوانینی هدایت می شود که نامیده می شوند ارشدیت اپراتورهادرک تقدم عملگرها برای املای صحیحعبارات - گاهی اوقات ممکن است نتیجه آنطور که انتظار می رود نباشد.

عبارت 42 + 6 * 10 را در نظر بگیرید. اگر 42 و 6 را جمع کنید و سپس حاصل را در 10 ضرب کنید، عدد 480 به دست می آید. یک جزء کامپایلر ویژه است - تحلیلگر واژگانی -مسئولیت ترتیب خواندن این کد را بر عهده دارد. این تحلیلگر واژگانی است که اولویت نسبی عملگرهای ناهمگن را در یک عبارت تعیین می کند. برای انجام این کار، از مقداری - اولویت - هر اپراتور پشتیبانی شده استفاده می کند. اپراتورهای با اولویت بالاتر ابتدا مجاز هستند. در مثال ما، عملگر * بر عملگر + اولویت دارد، زیرا * جذب می کند(اکنون این اصطلاح را توضیح خواهم داد) عملوندهای من قبل از + انجامش می دهد. توضیح در قواعد کلی حساب نهفته است: ضرب و تقسیم. همیشهبر جمع و تفریق ارجحیت دارد. برگردیم به مثال: می گویند عدد 6 بلعیده شدعملگر * در هر دو 42 + 6 * 10 و 42 * 6 + 10، بنابراین این عبارات معادل 42 + (6 * 10) و (42 * 6) + 10 هستند.

نحوه تعریف ارشدیت در C#

حال بیایید ببینیم که چگونه اولویت عملگر در C # تعریف می شود. اپراتورها در زیر به ترتیب تقدم نزولی فهرست شده اند (جدول 10-1). بعداً در مورد دسته های مختلف اپراتورهای پشتیبانی شده در C# به جزئیات بیشتری خواهم پرداخت.

برگه 10-1.تقدم عملگر در C#.

دسته اپراتور اپراتورها
ساده (x)، xy، f (x)، a [x]، x ++، x -، جدید، نوع، اندازه، علامت‌گذاری شده، بدون علامت
یگانه +، -،!، ++ x، - x، (T) x
ضربی *,/, %
افزودنی +, -
تغییر مکان «, »
نگرش <, >, <=, >=، است
برابری ==
منطقی و (AND) &
منطقی انحصاری OR (XOR) ^
منطقی یا (OR) 1
AND مشروط &&
IL AND مشروط (OR) II
وضعیت 9-
وظیفه = *= /= % = , + = , -= « = , » = , &=, ^ = , =

انجمن چپ و راست

Associativity تعیین می کند که کدام قسمت از عبارت ابتدا باید ارزیابی شود. به عنوان مثال، نتیجه عبارت فوق می تواند 21 یا 33 باشد، بسته به اینکه کدام ارتباط برای عملگر "-" استفاده می شود: چپ یا راست.

عملگر - دارای تداعی چپ است یعنی ابتدا 15-42 محاسبه می شود و سپس 6 از نتیجه کم می شود و اگر ارتباط سمت راست داشت ابتدا سمت راست عبارت (6-15) محاسبه می شود و سپس نتیجه محاسبه می شود. از 42 کم می شود.

همه عملگرهای باینری (عملگرهای با دو عملوند)، به جز عملگرهای انتساب، - چپ انجمنی،یعنی عبارات را از چپ به راست پردازش می کنند. بدین ترتیب، a + b+ با -همان (الف + ب) + ج،کجا برای اولین بار محاسبه می شود a + b،و سپس جمع اضافه می شود با.اپراتورهای واگذاری و عبارات مشروط - راست انجمنی،یعنی عبارات را از راست به چپ پردازش می کنند. به عبارت دیگر، a = b = cمعادل a = (ب= با).بسیاری از افراد زمانی که می خواهند چندین دستور انتساب را در یک خط قرار دهند به این موضوع برخورد می کنند، بنابراین بیایید به این کد نگاه کنیم:

با استفاده از سیستم؛

کلاس RightAssocApp (

خالی استاتیک عمومی Main () (

int a = 1; int b = 2; int c = 3;

Console.WriteLine ("a = (0) b = (1) c = (2>"، a, b, c)؛ a = b = c;

Console.WriteLine ("پس از" a = b = c -: a = (0) b = (1) c = (2) ", a, b, c);>>

نتیجه اجرای این مثال به شرح زیر است:

a = 1 b = 2 c = 3

بعد از "a = b = c": a = 3 b = 3 o = 3

ارزیابی عبارات از راست به چپ می‌تواند در ابتدا گیج‌کننده باشد، اما اجازه دهید اینگونه به آن بپردازیم: اگر عملگر انتساب به صورت ارتباطی رها می‌شد، کامپایلر ابتدا باید ارزیابی کند. a = b،سپس آبرابر 2 و سپس ب= s و در نتیجه بمی شود 3. نتیجه نهایی خواهد بود a = 2 b = 3 c = 3.بدیهی است که هنگام نوشتن این چیزی نیست که ما انتظار داریم آ= ب= با،و به همین دلیل است که عملگرهای انتساب و شرطی دارای حق تداعی هستند.

استفاده عملی

هیچ چیز دردسرسازتر از یافتن اشتباهی نیست که فقط به این دلیل که توسعه دهنده قوانین تقدم و تداعی را نمی دانست. من در کنفرانس های پستی با پیام هایی برخورد کردم که در آن افراد ظاهراً منطقی نوعی مکانیسم مستندسازی خود را پیشنهاد کردند - استفاده از فضاهایی برای نشان دادن اپراتورها که به نظر آنهادارای ارشدیت به عنوان مثال، از آنجایی که می دانیم عملگر ضرب بر عملگر جمع اولویت دارد، باید چیزی شبیه به این بنویسیم که در آن فاصله ها نشان دهنده ضمنیارشدیت:

a = b * c + d;

این رویکرد اساساً اشتباه است: کامپایلر نمی تواند کد را به درستی تجزیه کند اگر نحو خاص تعریف نشده باشد. کامپایلر کد را طبق قوانینی که توسط توسعه دهندگان کامپایلر تعریف شده است تجزیه می کند. از سوی دیگر، وجود دارد براکت های گردبرای نشان دادن صریح تقدم و تداعی استفاده می شود. مثلاً عبارت آ= b * c + dرا می توان به صورت بازنویسی کرد a = (b * c) + dیا چگونه آ= b * (c + d)و کامپایلر ابتدا عبارت پرانتز شده را ارزیابی می کند. اگر چند جفت پرانتز وجود داشته باشد، کامپایلر ابتدا عبارات پرانتز شده و سپس کل عبارت را بر اساس قوانین تقدم و انجمنی که شرح داده شده است، ارزیابی می کند.

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

اپراتورهای C #

صحیح ترین کار این است که اپراتورها را بر اساس ارشدیت در نظر بگیریم. در زیر رایج ترین اپراتورها را شرح خواهم داد.

اپراتورهای ساده

  • (x) این یک تغییر از عملگر پرانتز برای کنترل ترتیب ارزیابی است عملیات ریاضیو هنگام فراخوانی متدها
  • xy عملگر نقطه برای نشان دادن عضوی از یک کلاس یا ساختار استفاده می شود. اینجا NSیک موجودیت حاوی یک عضو را نشان می دهد در
  • f (x) این نوع عملگر پرانتز برای فهرست آرگومان های متد استفاده می شود.
  • اوه] براکت های مربعیبرای نمایه سازی یک آرایه استفاده می شود. هنگامی که اشیا را می توان به عنوان یک آرایه در نظر گرفت، از این براکت ها همراه با نمایه سازها نیز استفاده می شود. برای نمایه سازها، به فصل 7 مراجعه کنید.
  • х ++ در بخش "اپراتورهای افزایش و کاهش" به طور جداگانه در مورد عملگر افزایش صحبت خواهیم کرد.
  • x- عملگر کاهش بعداً مورد بحث قرار خواهد گرفت.
  • new این عملگر برای نمونه سازی اشیاء بر اساس تعریف کلاس استفاده می شود.

نوعی از

انعکاس(انعکاس) توانایی به دست آوردن اطلاعات نوع در زمان اجرا است. این اطلاعات شامل نام انواع، کلاس ها و اعضای ساختار است. V. چارچوب خالصاین قابلیت با کلاس مرتبط است سیستم. تایپ کنید.این کلاس ریشه همه عملگرهای بازتابی است و با استفاده از عملگر قابل بدست آوردن است نوعی از.ما در حال حاضر به جزئیات بازتاب نمی پردازیم (این کار را در فصل 16 انجام خواهیم داد)، اما در اینجا یک مثال ساده برای نشان دادن چقدر آسان بودن استفاده از عملگر آورده شده است. نوعی از"برای به دست آوردن تقریباً هر گونه اطلاعات در مورد یک نوع یا شی در طول اجرای برنامه:

با استفاده از سیستم؛

با استفاده از System.Reflection.

کلاس عمومی اپل (

عمومی int nSeeds;

خلأ عمومی رسیده ()

{

> >

کلاس عمومی TypeOfApp (

خالی استاتیک عمومی Main () (

نوع t = typeof (Apple);

string className = t.ToStringO;

Console.IgShip ("\ nInformation 0 class (O)", className);

Console.WriteLine ("\ nMeroflH (0)", className); کنسول. WriteLine ("--------")؛ روش‌های متدلینفو = t.GetMethodsO;

foreach (روش MethodInfo در متدها)

Console.WriteLine (روش حلقه ToSt ());

}

Console.WriteLine ("\ nBce Members (O)", className); کنسول. Writel_ine ("--------"); Memberlnfo allMembers = t.GetMembersO; foreach (عضو Memberlnfo در همه اعضا)

{

کنسول. WriteLine (member.ToStringO);

} > }

این برنامه شامل کلاس است سیبکه فقط دو عضو دارد: میدان n دانه هاو روش رسیدنابتدا با استفاده از اپراتور نوعی ازو نام کلاس را دریافت می کنم سیستم. نوع،که سپس در یک متغیر ذخیره می شود تی بادر این مرحله می توانم از شی استفاده کنم سیستم. تایپ کنیدبرای دریافت تمام متدها و اعضای یک کلاس سیب.این با استفاده از روش ها انجام می شود GetMethodsو GetMembersبه ترتیب. نتایج این روش ها در نمایش داده می شود دستگاه استانداردخروجی به صورت زیر

اطلاعات در مورد کلاس اپلروش های اپل

Int32 GetHashCodeQ

System.String ToStringQ

RipenO را باطل کنید

System.Type GetTypeO

همه اعضای اپل

Int32 nSeeds

Int32 GetHashCodeO

معادلهای بولی (System.Object)

System.String ToStringO

RipenO را باطل کنید

System.Type GetTypeO

قبل از ادامه، می خواهم به دو نکته اشاره کنم. ابتدا توجه داشته باشید که اعضای ارثی کلاس نیز استنباط می شوند. از آنجایی که کلاس به صراحت از کلاس دیگری مشتق نشده است، می دانیم که همه اعضا در کلاس تعریف نشده اند سیبارث بری از کلاس پایه ضمنی System.Object.دوم، شیء نوع سیستمرا می توان با روش به دست آورد GetType.این به ارث رسیده است System.Objectاین متد به شما اجازه می دهد با اشیا کار کنید، نه با کلاس ها. هر یک از دو قطعه زیر را می توان برای دریافت یک شی استفاده کرد سیستم. تایپ کنید.

IIدریافت یک شی System.Type بر اساس تعریف کلاس. نوع t1 = typeof (Apple);

// شی System.Type را از شی دریافت کنید. سیب سیب= AppleQ جدید؛ نوع t2 = apple.GetTypeO;

اندازه

اپراتور اندازهبرای بدست آوردن اندازه نوع مشخص شده در بایت استفاده می شود. در عین حال، فقط دو مورد را به خاطر بسپارید عوامل مهم... در ابتدا، اندازهفقط برای انواع ابعادی قابل اعمال است. بنابراین، در حالی که می توان از آن برای اعضای کلاس استفاده کرد، نمی توان از آن برای کلاس ها استفاده کرد. ثانیاً اندازهفقط می تواند در روش ها یا بلوک های کد مشخص شده به عنوان استفاده شود ناامن بادر فصل 17 با این نوع کدها آشنا می شویم. در اینجا مثالی از استفاده از عملگر آورده شده است. اندازهدر متدی از یک کلاس که به عنوان علامت گذاری شده است ناامن:

با استفاده از سیستم؛

کلاس BasicTypes (

// توجه: کد با استفاده از عملگر sizeof // باید به‌عنوان ناامن، ایستا ناامن عمومی خالی علامت گذاری شود ShowSizesQ (

Console.WriteLine ("\ nPa3Mephi انواع اصلی"); Console.WriteLine ("Pa3Mep short = (0)"، sizeof (کوتاه)); Console.WriteLine ("Pa3Mep int = (0)"، sizeof (int)); Console.Writel_ine ("Pa3Mep long = (0)", sizeof (طولانی)); Console.WriteLine ("Pa3Mep bool = (0)"، sizeof (bool)); ))

کلاس UnsafeUpp

{

MainQ خالی استاتیک عمومی ناامن

{

BasicTypes.ShowSizes ();

} }

در اینجا خروجی از این برنامه است:

سایز انواع پایه سایز کوتاه = 2 سایز int = 4 سایز بلند = 8 سایز bool = 1

اپراتور اندازهمی توان برای تعریف ابعاد نه تنها برای انواع توکار ساده، بلکه برای انواع ابعاد سفارشی مانند سازه ها نیز استفاده کرد. با این حال، نتایج اندازهممکن است واضح نباشد:

// با استفاده از عملگر sizeof. با استفاده از سیستم؛

ساختار StructWithNoMembers

ساخت StructWithMembers

{

شلوار کوتاه؛

int i;

طولانی 1;

bool b; )

ساختار CompositeStruct

{

StructWithNoMembers a; StructWithMembers b;

StructWithNoMembers c; )

کلاس UnSafe2App (

ناامن عمومی استاتیک void اصلی () (Console.WriteLine ("\ nPa3Mep StructWithNoMembers ساختار = (0)"،

sizeof (StructWithNoMembers)); Console.WriteLine ("\ nPa3Mep StructWithMembers ساختار = (0)"،

sizeof (StructWithMembers)); Console.WriteLine ("\ nPa3Mep CompositeStruct structure = (0)"،

sizeof (CompositeStruct))؛ ))

اگرچه می توان فرض کرد که این برنامه برای یک ساختار بدون عضو 0 خروجی می دهد (StructWithNoMembers)، 15 برای سازه ای با چهار عضو از انواع پایه (StructWithMembers)و 15 برای ساختاری که دو ساختار قبلی را جمع می کند (CompositeStruct)در واقع نتیجه به این صورت خواهد بود:

ساختار سایز StructWithNoMembers = ساختار سایز 1 StructWithMembers = 16

اندازه ساختار مرکب = 24

توضیح برای این روش حفظ ساختار است ساختکامپایلر در فایل خروجی که در آن کامپایلر توجیه و padding را اعمال می کند. به عنوان مثال، اگر ساختاری 3 بایت باشد و بر روی مرزهای 4 بایت تراز شود، کامپایلر به طور خودکار 1 بایت به ساختار اضافه می کند و عملگر اندازهنشان می دهد که اندازه ساختار 4 بایت است. به یاد داشته باشید که هنگام اندازه‌گیری ساختارها در C#، این را در نظر داشته باشید.

بررسی شدو بدون علامت

این دو عملگر هنگام انجام عملیات ریاضی، بررسی سرریز را کنترل می کنند.

عملگرهای ریاضی

سی #، مانند بسیاری از زبان های دیگر، از عملگرهای ریاضی پایه پشتیبانی می کند: ضرب (*)، تقسیم (/)، جمع (+)، تفریق (-) و مدول (%). هدف چهار عملگر اول از نام آنها مشخص است. عملگر مدول باقیمانده یک تقسیم عدد صحیح را تشکیل می دهد. در اینجا چند کد برای نشان دادن استفاده از عملگرهای ریاضی آورده شده است:

با استفاده از سیستم؛

کلاس MathOpsApp

{

MainQ خالی استاتیک عمومی

{

// کلاس System.Random بخشی از کتابخانه کلاس // .NET Framework است. در سازنده پیش فرض خود، // متد Next از تاریخ / زمان فعلی به عنوان // استفاده می کند. مقدار اولیه... رند تصادفی = RandomO جدید; int a, b, c;

a = rand.بعدی () % 100; // مقدار محدود 99. b = rand.NextO % 100; // مقدار حد 99.

Console.WriteLine ("a = (0) b = (1)"، a, b);

c = a * b;

Console.WriteLineC "a * b = (0)", c);

// توجه داشته باشید که در اینجا از اعداد صحیح استفاده می شود. // بنابراین، اگر a کمتر از b باشد، نتیجه همیشه // 0 خواهد بود. برای به دست آوردن نتیجه دقیق تر // باید از متغیرهایی ماننددو یا شناور، c = a / b; Console.WriteLineC "a / b = (0)"، c);

Console.WriteLineC "a + b = (0)", c);

Console.WriteLineC "a - b = (0)", c);

Console.WriteLineC "a X b = (0)", c); >>

اپراتورهای Unary

دو عملگر واحد وجود دارد: مثبت و منفی. عملگر unary minus به کامپایلر می گوید که عدد منفی است. بنابراین در کد زیر آبرابر -42 خواهد بود:

با استفاده از سیستم؛ با استفاده از سیستم؛

کلاس UnarylApp (

خلأ استاتیک عمومی اصلی ()

{

int a = 0;

a = -42;

Console.WriteLine ("(0)"، a); ))

با این حال، ابهام در این کد ظاهر می شود: using System;

کلاس Unary2App<

خالی استاتیک عمومی Main () (

int a; int b = 2; int c = 42;

a = b * -c;

Console.WriteLine ("(0)"، a); >>

اصطلاح آ= قبل از میلاد مسیحکاملا مشخص نیست باز هم استفاده از پرانتز این عبارت را روشن می کند:

// هنگام استفاده از پرانتز، واضح است که // b را در عدد منفی c ضرب می کنیم. a = b * (-c)؛

اگر منهای unary برمی گردد معنی منفیعملوند، ممکن است تصور شود که یک پلاس یکنواخت مثبت خواهد شد. با این حال، unary plus فقط عملوند را به شکل اصلی خود برمی گرداند و هیچ کار دیگری انجام نمی دهد، یعنی عملوند را تحت تأثیر قرار نمی دهد. به عنوان مثال، اجرای این کد مقدار -84 را به دست می دهد:

با استفاده از سیستم؛

کلاس UnarySapp (

MainQ خالی استاتیک عمومی (

a = b * (+ c);

Console.WriteLine ("(0)"، a); ))

برای بدست آوردن مقدار مثبت، از تابع استفاده کنید Math.Abs.این کد مقدار 84 را چاپ می کند:

با استفاده از سیستم؛

کلاس Unary4App

{

خلأ استاتیک عمومی اصلی ()

int a; int b = 2; int c = -42;

a = b * Math.Abs ​​(c); Console.Writel_ine ("(0)"، a); ))

آخرین عملگر یوناری که اشاره کردم T (x) است. این یک تغییر از عملگر پرانتز است که به شما امکان می دهد از یک نوع به نوع دیگر ارسال کنید. از آنجایی که با ایجاد یک تبدیل سفارشی می توان آن را بیش از حد بارگذاری کرد، در فصل 13 درباره آن بحث خواهیم کرد.

اپراتورهای واگذاری مرکب

عملگر انتساب مرکب -ترکیبی از عملگر باینری و عملگر انتساب (=) است. سینتکس این عملگرها به شرح زیر است:

کر = y

جایی که op -این اپراتور است توجه داشته باشید که هنگام انجام این کار، مقدار سمت چپ (lvalue)با راست جایگزین نشده است (rvalue)یک عبارت مرکب همان تأثیر را دارد:

x = x opدر

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

توجه کنید که گفتم "همان اثر را دارد." کامپایلر عبارتی مانند آن را ترجمه نمی کند x + = 5 اینچ NS= x + 5،او منطقی عمل می کند با توجه ویژهباید به مواردی مراجعه کنید که ارزشیک روش است کد را در نظر بگیرید:

با استفاده از سیستم؛

کلاس CompoundAssignmentlApp (

عناصر lnt محافظت شده؛

عمومی int GetArrayElementO

{

عناصر بازگشتی؛

}

CompoundAssignment1App () (

عناصر = int جدید;

عناصر = 42;

}

خالی استاتیک عمومی Main () (

برنامه CompoundAssignmentlApp = CompoundAsslgnment1App جدید ();

Console.WrlteLine ("(0>"، app.GetArrayElement ());

app.GetArrayElement () = app.GetArrayElement () + 5; Console.WriteLine ("(0)"، app.GetArrayElement ()); ). )

به فراخوانی متد خط برجسته توجه کنید Compound-AssignmentlApp.GetArrayElementو سپس عنصر اول را تغییر دادم - در اینجا من از نحو استفاده کردم:

x = x opدر

به این ترتیب کد MSIL تولید می شود: // تکنیک بی اثر: x = x op y.

روش عمومی hldebyslg static void اصلی () 11 مدیریت شد

Entrypolnt

// اندازه کد 79 (Ox4f) .maxstack 4

افراد محلی (کلاس CompoundAssignmentlApp V_0)

IL_0000: newobj instance void CompoundAssignmentlApp ::. Ctor () IL_0005: stloc.O IL_0006: Idstr "(OG IL_OOOb: ldloc.0 ILJJOOc: int32 call instance

CompoundAssignmentlApp :: GetArrayElementO

IL_0011: ldc.14.0

IL_0012: Idelema ["mscorlib"] System.Int32

IL_0017: جعبه [1 mscorlib "] System.Int32

IL_001c: فراخوانی void ["mscorlib 1] System.Console :: WriteLine (کلاس System.String، کلاس System.Object)

IL_0021: ldloc.0

IL_0022: نمونه تماس int32 CompoundAssignmentlApp :: GetArrayElementO

IL_0027: Idc.i4.0

IL_0028: ldloc.0

IL_0029: نمونه تماس int32 CompoundAssignmentlApp:: GetArrayElementO

IL_002e: Idc.i4.0

IL_002f: ldelem.14

IL_0030: ldc.14.5

IL_0031: اضافه کنید

IL_0032: stelem.14

IL_0033: Idstr "(0)"

IL_0038: ldloc.0

IL_0039: تماس بگیرید

نمونه int32 CompoundAssignmentlApp :: GetArrayElement () IL_003e: ldc.14.0

IL_003f: Idelema ["mscorlib"] Systera.Int32 IL_0044: جعبه ["msoorlib"] System.Int32 IL_0049: call void ["mscorlib"] System.Console :: WriteLine

(کلاس System.String، کلاس System.Object) IL_004e: ret

) // پایان روش "CompoundAssignmentlApp :: Main"!

به خطوط درهم آمیخته نگاه کنید: روش CompoundAssignmentlApp.Get-ArrayElementدر واقع دو بار نامیده می شود! این حداقل بگوییم بی اثر است و بسته به اینکه روش چه کار دیگری انجام می دهد، احتمالاً مضر است.

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

با استفاده از سیستم؛

کلاس CompoundAssignment2App (

عناصر int محافظت شده؛

عمومی int GetArrayElementO

عناصر بازگشتی؛

}

CompoundAssignment2App () (

عناصر = int جدید;

عناصر = 42;

}

خالی استاتیک عمومی Main () (

برنامه CompoundAssignment2App = جدید CompoundAssignment2App ();

Console.WriteLine ("(0)"، app.GetArrayElement ());

app.GetArrayElement () + = 5; Console.WriteLine ("(0)"، app.GetArrayElement ()); ))

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

// تکنیک کارآمدتر: x op = y.

روش عمومی hidebysig static void اصلی () مدیریت شد

\ {

\ .نقطه ورود

I // اندازه کد 76 (Ox4c) \ .maxstack 4

افراد محلی (کلاس CompoundAssignmentlApp V_0، int32 V_1) \ IL_0000: نمونه newobj void CompoundAssignmentlApp ::. Ctor () \ IL_0005: stloc.O 1 IL_0006: Idstr "(0)" 1 IL_OOOb: ldloc.0 IL_OOOc: نمونه تماس int32

CompoundAssignmentlApp :: GetArrayElementO IL_0011: Idc.i4.0

IL_0012: Idelema [mscorlib "] System.Int32 IL_0017: box [> mscorlib -] System.Int32 lL_001c: call void [" mscorlib "] System.Console :: WriteLine

(کلاس System.String، کلاس System.Object) IL_0021: ldloc.0 IL_0022: نمونه تماس int32

CompoundAssignmentlApp :: GetArrayElement ()

IL_0027: dup

IL_0028: stloc.1

IL_0029: Idc.i4.0

IL_002a: ldloc.1

IL_002b: Idc.i4.0

IL_002c: ldelem.14

IL_002d: ldc.14.5

IL_002e: اضافه کنید

IL_002f: stelem.14

IL_0030: Idstr "(0)"

IL_0035: ldloc.0

IL_0036: نمونه تماس int32

CompoundAssignmentlApp :: GetArrayElementO IL_003b: Idc.i4.0

IL_003c: Idelema ["mscorlib"] System.Int32

IL_0041: جعبه [mscorlib "] System.Int32

IL_0046: call void ["mscorlib"] System.Console :: WriteLine

(کلاس System.String، کلاس System.Object)

IL_004b: ret) // پایان روش "CompoundAssignmentlApp :: Main"

می توانید دستور MSIL استفاده شده را مشاهده کنید فریب دادنآیتم بالای پشته را کپی می کند، بنابراین یک کپی از مقدار بازگردانده شده توسط متد ایجاد می کند CompoundAssignmentlApp.Get Array Element. من

این نشان می دهد که اگرچه در اصل x + = yمعادل x = x + y،کد MSIL در هر دو مورد متفاوت است. این تمایز شما را به این فکر می‌اندازد که در هر مورد از کدام نحو استفاده کنید. یک قانون سرانگشتی و توصیه من این است که هر زمان و هر جا که ممکن است از عملگرهای انتساب ترکیبی استفاده کنید.

عملگرهای افزایش و کاهش

در C معرفی شد و به C ++ و پورت شد اپراتورهای جاواافزایش 1 و کاهش به شما اجازه می دهند بطور خلاصه بیان کنید که می خواهید یک مقدار عددی را 1 کم یا زیاد کنید. یعنی / ++ معادل اضافه کردن 1 به مقدار فعلی / " است.

وجود دو شکل عملگر افزایش و کاهش گاهی گیج کننده است. پیشوندو پسوندانواع این عملگرها در لحظه تغییر مقدار متفاوت است. در نسخه پیشوند عملگرهای افزایش و کاهش (++ ai - aبه ترتیب) ابتدا عملیات انجام می شود و سپس مقدار ایجاد می شود. در نسخه postfix (a ++و آ-)ابتدا مقدار ایجاد می شود و سپس عملیات انجام می شود. بیایید یک مثال را در نظر بگیریم:

با استفاده از سیستم؛

کلاس IncDecApp (

عمومی استاتیک void Foo (int j)

{

Console.WriteLine ("IncDecApp.Foo j = (0)"، j);

>

خالی استاتیک عمومی Main () (

int i = 1;

Console.WriteLineC "flo call to Foo (i ++) = (0)", i);

Console.WriteLine ("پس از تماس با Foo (i ++) = (0)"، i);

Console.WriteLine ("\ n");

\ Console.WriteLineC "flo call to Foo (++ i) = (0)", i);

\ Foo (++ l)؛

\ Console.WrlteLine ("پس از تماس با Foo (++ i) = (0)"، i);

l نتیجه به این صورت خواهد بود:

قبل از فراخوانی Foo (i ++) = 1

IncDecApp.Foo j = 1

پس از فراخوانی Foo (i ++) = 2

قبل از فراخوانی Foo (-n-i) = 2

IncDecApp.Foo j = 3

پس از فراخوانی Foo (++ i) = 3

تفاوت این است چه زمانیمقدار ایجاد می شود و عملوند اصلاح می شود. هنگام تماس فو (i ++)مقدار / "به متد ارسال می شود (بدون تغییر). فوو بعد ازمتد return / با 1 افزایش می یابد. به کد MSIL بالا نگاه کنید: دستور اضافه کردنپس از فشار دادن مقدار به پشته اجرا می شود.

IL.0013: ldloc.0

IL.0014: dup

IL_0015: Idc.i4.1

IL_0016: اضافه کنید

IL_0017: stloc.O

IL_0018: call void IncDecApp :: Foo (int32)

حالا بیایید به فرم عملگر پیشوند استفاده شده در تماس نگاه کنیم فو (++ a).در این صورت کد MSIL متفاوت خواهد بود. در این حالت دستور اضافه کردنانجام قبل ازچگونه مقدار برای فراخوانی متد بعدی به پشته فشار داده می شود فو

IL.0049: ldloc.0

IL_004a: Idc.i4.1

IL_004b: اضافه کنید

IL_004c: dup

IL_004d: stloc.O

IL_004e: call void IncDecApp :: Foo (int32)

عملگرهای رابطه ای

اکثر عملگرها مقادیر عددی را برمی گردانند. در مورد عملگرهای رابطه ای، آنها یک نتیجه بولی ایجاد می کنند. به جای / به جای انجام عملیات ریاضی روی مجموعه ای از عملوندها، / عملگرهای رابطه ای رابطه بین عملوندها و برگشتمعنی درست است، واقعی،اگر نسبت درست باشد، نادرست -اگر / نادرست است.

اپراتورهای مقایسه

به عملگرهای رابطه ای فراخوانی شده است عملگرهای مقایسه،مراجعه کنید) - "کمتر" است (<), «меньше или равно» (<=), «больше» (>)، بزرگتر یا مساوی (> =)، برابر (==)، و نه برابر (! =). اعمال این عملگرها برای اعداد قابل درک است، اما زمانی که با اشیاء استفاده می شود، اجرای آنها چندان واضح نیست. در اینجا یک مثال است:

با استفاده از سیستم؛

کلاس NumericTest (

عمومی NumericTest (int 1)

{

this.i = i;

>

محافظت شده int 1; )

کلاس RelationalOpslApp (

خالی استاتیک عمومی Main () (

NumericTest testl = NumericTest جدید (42); NumericTest test2 = NumericTest جدید (42);

Console.WriteLine ("(0)", testl == test2); >)

اگر یک برنامه نویس جاوا هستید، می دانید که در اینجا چه اتفاقی قرار است بیفتد. با این حال، برنامه نویسان ++C به احتمال زیاد از دیدن نتیجه شگفت زده خواهند شد نادرستاجازه دهید به شما یادآوری کنم که وقتی یک نمونه از یک شی را ایجاد می کنید، پیوندی به آن دریافت می کنید. این به این معنی است که وقتی با عملگر رابطه ای مواجه می شود که دو شی را با هم مقایسه می کند، کامپایلر C# نه محتویات اشیاء، بلکه آدرس های آنها را مقایسه می کند. برای درک بهتر این موضوع، کد MSIL را در نظر بگیرید:

\ .method public hldebysig static void MainQ مدیریت شد

\ .نقطه ورود

\ // اندازه کد 39 (0x27)

1. maxstack 3

افراد محلی (کلاس NumericTest V_0، \ کلاس NumericTest V_1، 1 bool V_2)

ILJOOO: Idc.i4.s 42

1L_0002: نمونه newobj void NumericTest ::. Ctor (int32)

IL_0007: stloc.O

IL_0008: Idc.i4.s 42

IL_OOOa: نمونه newobj void NumericTest ::. Ctor (int32)

IL_OOOf: stloc.1

IL_0010: Idstr "(0)"

IL_0015: ldloc.0

IL_0016: ldloc.1

IL_0017: eeq

IL_0019: stloc.2

IL_001a: Idloca.s V_2

IL_001c: جعبه ["mscorlib"] System.Boolean

IL_0021: call void ["mscorlib"] System.Console :: WriteLine

(کلاس System.String، کلاس System.Object)

IL_0026: ret) // انتهای روش "RelationalOpslApp :: Main"

به خط نگاه کن محلی ها.کامپایلر نشان می دهد که روش اصلیسه متغیر محلی دو مورد اول اشیا هستند تست عددی،یک سوم یک متغیر بولی است. حالا بریم سراغ خطوط IL_0002و IL_0007.اینجاست که شیء نمونه سازی می شود تستل،و با آن پیوند دهید stlocدر اولین متغیر محلی ذخیره می شود. با این حال، مهم است که MSIL آدرس شی جدید ایجاد شده را حفظ کند. سپس در خطوط IL_OOOaو IL_OOO ازکدهای MSIL را برای ایجاد شی می بینید تست 2و ذخیره مرجع برگشتی در یک متغیر محلی دوم. در نهایت، در خطوط 1LJ) 015و IL_0016متغیرهای محلی توسط دستور به پشته فشار داده می شوند Idloc،و در خط IL_0017فرمان خاکستریدو مقدار را در بالای پشته مقایسه می کند (به عنوان مثال، ارجاعات شی testlو testl).مقدار بازگشتی در سومین متغیر محلی ذخیره می شود و سپس با روش نمایش داده می شود سیستم.کنسول. WriteLine.

اما چگونه می توان اعضای دو شی را با هم مقایسه کرد؟ پاسخ این است که از کلاس پایه ضمنی تمام اشیاء .NET Framework استفاده کنید. یعنی برای این اهداف کلاس System.Objectروشی وجود دارد برابر است.به عنوان مثال، کد زیر محتویات اشیاء و خروجی ها را همانطور که انتظار دارید مقایسه می کند. درست: من

با استفاده از سیستم؛ /

کلاس RelationalOps2App

(/ public static void main () (

Console.WriteLine ("(0)"، testl.Equals (test2));

مثال RelationalOpslApp از یک کلاس "homemade" استفاده می کند (Nu-mericTest) ودر مثال دوم - کلاس دات نت (اعشاری).نکته این است که روش System.Object.Equalsبرای انجام مقایسه اعضای واقعی باید نادیده گرفته شود. از این رو روش برابر استبا کلاس Nume-ric Testکار نخواهد کرد زیرا ما روش را لغو نکرده ایم. و اینجا کلاس است اعشاریروشی را که به ارث می برد نادیده می گیرد برابر است،و در این صورت همه چیز کار خواهد کرد.

روش دیگر برای مقایسه اشیاء استفاده است اضافه بار اپراتور(بارگذاری بیش از حد اپراتور). بارگذاری بیش از حد اپراتور، عملیات انجام شده بر روی اشیاء از یک نوع خاص را تعریف می کند. مثلا برای اشیا رشتهعملگر + جمع را انجام نمی دهد، بلکه رشته ها را به هم متصل می کند. ما بارگذاری بیش از حد اپراتور را در فصل 13 پوشش خواهیم داد.

عملگرهای انتساب ساده

مقدار سمت چپ عملگر انتساب فراخوانی می شود ارزش،و در سمت راست - rvalueمانند rvalueمی تواند هر ثابت، متغیر، عدد یا عبارتی باشد که نتیجه آن با آن سازگار باشد ارزشدر همین حال ارزشباید متغیری از نوع خاصی باشد. نکته این است که مقدار از سمت راست به چپ کپی می شود. بنابراین، یک فضای آدرس فیزیکی باید برای مقدار جدید اختصاص داده شود. به عنوان مثال، می توانید بنویسید / "= 4, از آنجایی که بسته به نوع /، فضایی برای / در حافظه وجود دارد - چه روی پشته یا روی پشته - بسته به نوع /. و اپراتور اینجاست 4 = 1 نمی توان اجرا کرد زیرا 4 یک مقدار است، نه متغیری که محتویات آن در حافظه قابل تغییر است. به هر حال، من توجه می کنم که در C # به عنوان ارزشمی تواند یک متغیر، ویژگی یا نمایه ساز باشد. برای اطلاعات بیشتر در مورد ویژگی ها و نمایه سازها، به فصل 7 مراجعه کنید. در این فصل، من از متغیرها برای سادگی استفاده می کنم. اگر با تکلیف مقادیر عددیهمه چیز به اندازه کافی واضح است، با اشیا پیچیده تر است. اجازه دهید به شما یادآوری کنم که وقتی با اشیا سروکار دارید، موارد غیر پشته ای را دستکاری می کنید که به راحتی کپی و جابجا می شوند. در مورد اشیا، شما در واقع فقط به برخی از موجودیت هایی که حافظه به صورت پویا برای آنها تخصیص داده شده است ارجاع دارید. بنابراین، هنگامی که می‌خواهید یک شی (یا هر نوع مرجع) را به یک متغیر اختصاص دهید، داده‌ها مانند انواع بعدی کپی نمی‌شوند، بلکه ارجاعات کپی می‌شوند.

فرض کنید دو شی دارید: testlو تست 2.اگر مشخص کنید testl= test2، testlکپی نخواهد بود تست 2.مطابقت خواهند داشت! یک شی testlبه همان حافظه اشاره می کند تست 2،و هر گونه تغییر در شی testlمنجر به تغییرات خواهد شد تست 2.در اینجا برنامه ای وجود دارد که این را نشان می دهد:

با استفاده از سیستم؛

کلاس فو (

عمومی int i; )

کلاس RefTestlApp (

MainO خالی استاتیک عمومی (

Foo testl = Foo جدید (); testl.i = 1;

Foo test2 = Foo جدید (); test2.i = 2;

Console.WriteLine ("قبل از تخصیص اشیا"); Console.WriteLine ("test1.i = (0>"، testl.i); Console.WriteLine ("test2.i = (0)"، test2.i); Console.WriteLine ("\ n");

testl = test2;

Console.Writel_ine ("پس از انتساب اشیا");

Console.WriteLine ("test1.i = (0)"، testl.i); Console.WriteLine ("test2.i = (0)"، test2.i); Console.WriteLine ("\ n");

testl.i = 42; ;"

Console.WriteLine ("پس از تغییر فقط عضو TEST1"); Console.WriteLine ("test1.i = (0)"، testl.i); Console.WriteLine ("test2.i = (0)"، test2.i); Console.WriteLine ("\ n"); ))

با اجرای این کد خواهید دید:

قبل از اختصاص یک شی

test1.i = 1

test2.i = 2

پس از اختصاص یک شی

testt.i = 2

test2.i = 2

پس از تغییر فقط عضو TEST1

test1.i = 42

test2.i = 42

بیایید ببینیم در هر مرحله از این مثال چه اتفاقی می افتد. فو -این یک کلاس k ساده با تنها یک عضو، / است. در متد Main دو نمونه از این کلاس ایجاد می شود: testlو تست 2- و اعضای آنها منبه ترتیب روی 1 و 2 تنظیم می شوند. سپس این مقادیر و همانطور که انتظار می رود، خروجی می شوند testl.iبرابر با 1، a test2.i- 2. و اینجا سرگرمی شروع می شود! V خط بعدیهدف - شی testlاختصاص داده تست 2.خوانندگان جاوا می دانند که در ادامه چه خبر است. با این حال، بیشتر برنامه نویسان C ++ انتظار عضو / شی را دارند testlاکنون با عضوی از شیء برابر است تست 2(با فرض اینکه وقتی چنین برنامه ای کامپایل می شود، نوعی عملگر برای کپی اعضای شی اجرا می شود). به نظر می رسد نتیجه نمایش داده شده این را تایید می کند. با این حال، در واقعیت، ارتباط بین اشیاء در حال حاضر بسیار عمیق تر است. مقدار 42 را به عضو اختصاص دهید testl.iو دوباره نتیجه را چاپ کنید. و؟! وقتی جسم تغییر می کند testlتغییر کرد و testZاین اتفاق به دلیل این واقعیت است که جسم testlبیشتر نه. پس از تعیین آن تست 2یک شی testlاز بین می رود زیرا دیگر توسط برنامه ارجاع داده نمی شود و در نتیجه توسط جمع کننده زباله (GC) "پاکسازی" می شود. اکنون testlو تست 2به همان حافظه روی پشته اشاره کنید. بنابراین، هنگامی که یک متغیر تغییر می کند، کاربر تغییر دیگری را نیز مشاهده می کند.

به دو خط آخر در حال چاپ توجه کنید: اگرچه فقط مقدار در کد تغییر کرده است testl.i،معنی test2.iنیز تغییر کرد. بار دیگر، هر دو متغیر اکنون به یک مکان حافظه اشاره می کنند - این همان رفتاری است که برنامه نویسان جاوا انتظار دارند. با این حال، این به هیچ وجه انتظارات توسعه دهندگان C ++ را برآورده نمی کند، زیرا در این زبان دقیقاً کپی کردن اشیا انجام می شود: هر متغیر دارای کپی منحصر به فرد خود از اعضای خود است و تغییرات در یک شی تأثیری بر دیگری ندارد. از آنجایی که این کلید درک نحوه کار اشیاء در #C است، بیایید کمی منحرف شویم و ببینیم وقتی یک شی را به یک متد ارسال می‌کنید چه اتفاقی می‌افتد:

با استفاده از سیستم؛

کلاس فو (

عمومی int i; )

کلاس RefTest2App (

public void ChangeValue (Foo f)

{

f.i = 42;

}

خالی استاتیک عمومی Main () (

برنامه RefTest2App = RefTest2App جدید ();

تست Foo = Foo جدید (); test.i = 6;

Console.WriteLine ("قبل از فراخوانی متد")؛ Console.WriteLine ("test.i = (0)"، test.i); Console.WriteLine ("\ n");

app.ChangeValue (تست)؛

Console.WriteLine ("پس از فراخوانی روش"); Console.WriteLine ("test.i = (0)"، test.i); Console.WriteLine ("\ n"); >)

در اکثر زبان های غیر از جاوا، این کد شی ایجاد شده را کپی می کند تست درپشته متد محلی RefTest2App.ChangeValue.در این مورد، شی تست،به روش ایجاد شده است اصلی،هرگز تغییرات در / شی ایجاد شده در متد را مشاهده نخواهد کرد ChangeValue.با این حال، یک بار دیگر تکرار می کنم که روش اصلییک ارجاع به یک شیء تخصیص داده شده توسط پشته ارسال می کند تست.زمانی که روش تغییر ارزشمتغیر محلی خود // را دستکاری می کند، همچنین مستقیماً شی را دستکاری می کند تستروش اصلی

بیایید خلاصه کنیم

نکته اصلی در هر زبان برنامه نویسی روش انجام عملیات انتساب، ریاضی، منطقی و رابطه است - همه آنچه برای کار لازم است. برنامه های کاربردی واقعی... در کد، این عملیات توسط عملگرها نشان داده می شود. عوامل موثر بر اجرای عملگرها عبارتند از تقدم و ارتباط (راست و چپ) عملگرها. مجموعه قدرتمند عملگرهای از پیش تعریف شده در C# را می توان با پیاده سازی های تعریف شده توسط کاربر گسترش داد که در فصل 13 در مورد آنها صحبت خواهیم کرد.

آخرین به روز رسانی: 1396/06/19

عبارات شرطی مجموعه جداگانه ای از عملیات هستند. چنین عملیاتی یک مقدار بولی، یعنی مقداری از نوع bool را برمی گرداند: اگر عبارت درست باشد true و اگر عبارت نادرست باشد، false. چنین عملیاتی شامل مقایسه و عملیات منطقی است.

عملیات مقایسه

عملیات مقایسه دو عملوند را مقایسه می‌کند و یک مقدار bool برمی‌گرداند - اگر عبارت درست باشد true و اگر عبارت نادرست باشد false.

    دو عملوند را برای برابری مقایسه می کند. اگر مساوی باشند، عملیات true و اگر مساوی نباشند، false بر می گردد:

    ب // نادرست

    دو عملوند را با هم مقایسه می کند و اگر عملوندها مساوی نباشند true و اگر مساوی باشند false را برمی گرداند.

    Int a = 10; int b = 4; bool c = a! = b; // واقعی bool d = a! = 10; // نادرست

    کمتر از عملیات اگر عملوند اول کمتر از دومی باشد true و اگر عملوند اول بزرگتر از دومی باشد false را برمی‌گرداند:

    Int a = 10; int b = 4; bool c = a< b; // false

    بزرگتر از عملیات دو عملوند را مقایسه می کند و اگر عملوند اول بزرگتر از دومی باشد true را برمی گرداند، در غیر این صورت false را برمی گرداند:

    Int a = 10; int b = 4; bool c = a> b; // true bool d = a> 25; // نادرست

    کمتر یا مساوی با عملکرد. دو عملوند را با هم مقایسه می کند و اگر عملوند اول کوچکتر یا مساوی دومی باشد مقدار true را برمی گرداند. در غیر این صورت false برمی گرداند.

    Int a = 10; int b = 4; bool c = a<= b; // false bool d = a <= 25; // true

    بزرگتر یا مساوی با عملکرد. دو عملوند را با هم مقایسه می کند و اگر عملوند اول بزرگتر یا مساوی دومی باشد true را برمی گرداند، در غیر این صورت false را برمی گرداند:

    Int a = 10; int b = 4; bool c = a> = b; // واقعی bool d = a> = 25; // نادرست

عملیات<, > <=, >= بر == و! = ارجحیت دارد.

عملیات منطقی

C# همچنین عملگرهای منطقی را تعریف می کند که یک مقدار bool را نیز برمی گرداند. آنها مقادیر bool را به عنوان عملوند می گیرند. معمولاً برای روابط اعمال می شود، آنها چندین عملیات مقایسه را ترکیب می کنند.

    اضافه منطقی یا منطقی OR. اگر حداقل یکی از عملوندها true را برگرداند true را برمی گرداند.

    Bool x1 = (5> 6) | (4< 6); // 5 >6 - نادرست، 4< 6 - true, поэтому возвращается true bool x2 = (5 >6) | (4> 6)؛ // 5> 6 - نادرست، 4>

    ضرب منطقی یا عملیات AND منطقی اگر هر دو عملوند به طور همزمان درست باشند، true را برمی‌گرداند.

    Bool x1 = (5> 6) و (4< 6); // 5 >6 - نادرست، 4< 6 - true, поэтому возвращается false bool x2 = (5 < 6) & (4 < 6); // 5 < 6 - true, 4 < 6 - true, поэтому возвращается true

    عملیات اضافه منطقی اگر حداقل یکی از عملوندها true را برگرداند true را برمی گرداند.

    Bool x1 = (5> 6) || (4< 6); // 5 >6 - نادرست، 4< 6 - true, поэтому возвращается true bool x2 = (5 >6) || (4> 6)؛ // 5> 6 false است، 4> 6 ​​false است، بنابراین false برگردانده می شود

    عملیات ضرب منطقی اگر هر دو عملوند همزمان درست باشند مقدار true را برمی گرداند.

    Bool x1 = (5> 6) && (4< 6); // 5 >6 - نادرست، 4< 6 - true, поэтому возвращается false bool x2 = (5 < 6) && (4 < 6); // 5 < 6 - true, 4 >6 درست است، بنابراین true برگردانده می شود

    عملیات نفی منطقی بر روی یک عملوند انجام می شود و اگر عملوند false باشد true را برمی گرداند. اگر عملوند true باشد، عملیات false را برمی گرداند:

    Bool a = درست; bool b = a; // نادرست

    عملیات انحصاری OR. اگر عملوند اول یا دوم (اما نه هر دو) درست باشد true برمی‌گرداند، در غیر این صورت false را برمی‌گرداند.

    Bool x5 = (5> 6) ^ (4< 6); // 5 >6 - نادرست، 4< 6 - true, поэтому возвращается true bool x6 = (50 > 6) ^ (4 / 2 < 3); // 50 >6 - درست، 4/2< 3 - true, поэтому возвращается false

در اینجا ما دو جفت عملیات داریم | و || (و همچنین & و &&) کارهای مشابهی انجام می دهند، اما یکسان نیستند.

در عبارت z = x | y; هر دو x و y محاسبه خواهند شد.

در عبارت z = x || y; ابتدا مقدار x محاسبه می شود و اگر درست باشد، محاسبه مقدار y دیگر معنی ندارد، زیرا در هر صورت، z از قبل برابر با true خواهد بود. Y فقط در صورتی محاسبه می شود که x نادرست باشد

همین امر در مورد جفت عملیات & / && صدق می کند. عبارت z = x هر دو x و y را ارزیابی می کند.

در عبارت z = x & ابتدا مقدار x محاسبه می شود و اگر نادرست باشد، محاسبه مقدار y دیگر معنی ندارد، زیرا در مورد ما، در هر صورت، z قبلا برابر با false خواهد بود. . Y فقط در صورتی محاسبه می شود که x درست باشد

بنابراین، عملیات || و && در محاسبات راحت‌تر هستند، زیرا به شما امکان می‌دهند زمان ارزیابی مقدار یک عبارت را کاهش دهید و در نتیجه عملکرد را افزایش دهید. و عملیات | و & برای انجام عملیات بیتی روی اعداد مناسب ترند.

عملگر && بر عملگر || اولویت دارد. پس در عبارت true || true && false عبارت فرعی true && false ابتدا اجرا می شود.

مقالات مرتبط برتر