زنگ سی شارپ – قسمت شانزدهم

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


مسعود درویشیان 10 دیدگاه سی شارپ Thursday, 22nd November , 2012 24470 بازدید

در برنامه‌نویسی بارها مواردی به‌وجود می‌آید که یک نوع از یک متغیر را به نوع دیگری اختصاص دهید. به‌عنوان مثال گاهی پیش می‌آید که مقدار یک int را به یک float اختصاص دهید.

زنگ سی‌شارپ - قسمت شانزدهم

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

int i;
double b;

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

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

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

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

  • Implicit
  • Explicit

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

  • هر دو نوع داده با هم سازگاری داشته باشند.
  • بازه و محدوده‌ی نوع مقصد بزرگ‌تر از بازه و محدوده‌ی نوع مبدا باشد.

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

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

using System;
class Example
{
    static void Main()
    {
        int i = 300;
        byte b = 255;

        /* It's a implicit conversion */
        i = b; // assing a byte to an int

        Console.WriteLine("We assing a byte to an int: " + i);
    }
}

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

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

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

using System;
class Example
{
    static void Main()
    {
        /* This program will not compile */

        int i = 150;
        byte b;

        b = i; // Illegal!!!

        Console.WriteLine(b);
    }
}

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

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 شده است.

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

using System;
class Example
{
    static void Main()
    {
        double x, y;

        x = 25.3;
        y = 5.1;

        int result = (int) (x / y);
        Console.WriteLine("The result is " + result);
    }
}

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

در cast کردن اگر نوع متغیر مقصد کوچک‌تر از مبدا باشد ممکن است بخشی از اطلاعات از بین برود. همچنین هنگام cast کردن مقادیر اعشاری به عدد صحیح قسمت اعشاری آن‌ها از بین می‌رود. برای مثال هنگام cast کردن مقدار 1.23 به عدد صحیح نتیجه 1 خواهد بود. همچنین هنگامی‌که قصد دارید نوع int را در نوع byte قرار دهید مقداری از اطلاعات ممکن از از بین برود چراکه نهایت مقداری که byte می‌تواند ذخیره کند عدد 255 است:

using System;
class Example
{
    static void Main()
    {
        int anOkayInt = 345;
        byte aBadByte = (byte)anOkayInt;

        Console.WriteLine(aBadByte);
    }
}

خروجی این برنامه عدد 89 است. اگر قصد داشته باشید عدد 256 را از طریق cast کردن در  byteذخیره کنید، عددی که ذخیره می‌شود صفر است. اگر 257 را در byte ذخیره کنید، عدد 1 ذخیره می‌شود و همین‌طور که می‌بینید ذخیره‌ی عدد 345 در byte موجب شده تا عدد 89 در آن قرار گیرد که دقیقاً معادل تفریق 345 و 256 است.

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

using System;
class Exampe
{
    static void Main()
    {
        double x, y;
        byte b;
        int i;
        char ch;
        uint u;
        short s;
        long l;

        x = 10.0;
        y = 3.0;

        // Cast double to int, fractional component lost.
        i = (int)(x / y);
        Console.WriteLine("Integer outcome of x / y: " + i);
        Console.WriteLine();

        // Cast an int into a byte, no data lost.
        i = 255;
        b = (byte)i;
        Console.WriteLine("b after assigning 255: " + b +
        " -- no data lost.");

        // Cast an int into a byte, data lost.
        i = 257;
        b = (byte)i;
        Console.WriteLine("b after assigning 257: " + b +
        " -- data lost.");
        Console.WriteLine();

        // Cast a uint into a short, no data lost.
        u = 32000;
        s = (short)u;
        Console.WriteLine("s after assigning 32000: " + s +
        " -- no data lost.");

        // Cast a uint into a short, data lost.
        u = 64000;
        s = (short)u;
        Console.WriteLine("s after assigning 64000: " + s +
        " -- data lost.");
        Console.WriteLine();

        // Cast a long into a uint, no data lost.
        l = 64000;
        u = (uint)l;
        Console.WriteLine("u after assigning 64000: " + u +
        " -- no data lost.");

        // Cast a long into a uint, data lost.
        l = -12;
        u = (uint)l;
        Console.WriteLine("u after assigning -12: " + u +
        " -- data lost.");
        Console.WriteLine();

        // Cast a byte into a char.
        b = 88; // ASCII code for X
        ch = (char)b;
        Console.WriteLine("ch after assigning 88: " + ch);
    }
}

خروجی:

بهتر است هر قسمت این برنامه را شرح دهیم. در قسمت اول (x / y) به int تبدیل شده است. در این‌جا قسمت اعشاری نتیجه‌ی تقسیم از بین می‌رود. در قسمت بعد عدد صحیح 255 را به byte اختصاص داده‌ایم و به این علت که byte توانایی نگه‌داری این مقدار را دارد، هیچ اطلاعاتی از بین نمی‌رود اما با این حال به cast کردن نیاز است چراکه به‌صورت implicit نمی‌توان int را به byte کانورت کرد. در قسمت بعدتر 257 را به byte اختصاص داده‌ایم که موجب از بین رفتن اطلاعات می‌شود.

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



نویسنده / مترجم : مسعود درویشیان

علاقه مند به موسیقی و برنامه نویسی بازی


10 دیدگاه برای این نوشته ثبت شده است


  1. مهدی
    23 November 2012

    سلام بازم ممنون از آموزش خیلی خوبتون .اگه میشه بحث آرایه هارو هم مطرح کنید.ودر مورد ماتریس ها توضیح بدهید.




    • مسعود درویشیان
      23 November 2012

      سلام. مبحث آرایه‌های یک بعدی و دو بعدی در قسمت‌های 17، 18 و 19 مورد بحث قرار می‌گیره




  2. داوود
    24 November 2012

    با سلام خدمت شما آقای مهندس؛
    دستتون درد نکنه بابت زحماتی که متحمل میشید.

    چند سوال در اینجا برام پیش اومد؟
    الف – بعنوان مثال اگه ما دو تا متغیر از نوع int و با مقادیر 7 و 3 داشته باشیم؛ و اونها رو بر همدیگه تقسیم کنیم، نتیجه اعشاری میشه، ولی چرا با اینکه اگه نتیجه رو از نوع int بگیریم ، برنامه ایرادی نمیگیره؟ بخاطر همون موضوعی که گفتید هست؟ یعنی چون نتیجه که اعشاری میشه از Int کوچیکتره و همنوع هم هستند؟ولی عکس این موضوع کار نمیکنه! یعنی اگه ما دو تا متغیر رو از نوع float بگیریم ونتیجه رو از نوع int برنامه خطا میگیره! آیا بدلیل هم نوع نبودنشونه؟ اگه اینجوری باشه پس اولی رو هم نباید جوا ب بده.

    ب – جهت روشن تر شدن موضوع در مثال اول b=i ؛ مقصد در طرف چپ قرار داره دیگه درسته ؟
    در این نوع عبارات مقصد همیشه در طرف چپ واقع شده؟

    ج- میشه انواع نوعهای سازگار رو بگید؟

    د- در این جدول http://msdn.microsoft.com/en-US/library/kca3w8x6%28v=vs.80%29.aspx
    میشه گفت عمل casting (نوعهای سمت راست به نوعهای سمت چپ) به صورت implicit اتفاق میفته؟ یعنی نیازی به casting توسط ما نیست.
    یا در این جدول این اتفاق میفته: http://msdn.microsoft.com/en-us/library/k1e94s7e%28v=vs.80%29.aspx

    در واقع من میخوام 2 تا جدول داشته باشم که بدونم کدوم نوع رو در تبدیل به نوع دیگه نیاز به عمل casting دارم و کدوم نوع رو ندارم؟ (یعنی کدوم اتوماتیک انجام میشه و کدوم نه؟)

    ببخشید که سوالات زیادی ازتون پرسیدم.امیدوارم بتونم منظورمو واضح رسونده باشم.

    موفق باشید.




    • مسعود درویشیان
      3 December 2012

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

      از sbyte به short ،int ،long ،float ،double ،decimal
      از byte به short ،ushort ،int ،uint ،long ،ulong ،float ،double ،decimal
      از short به int ،long ،float ،double ،decimal
      از ushort به int ،uint ،long ،ulong، float، double ،decimal
      از int به long ،float ،double ،decimal
      از uint به long ،ulong ،float ،double ،decimal
      از long به float ،double ،decimal
      از ulong به float ،double ،decimal
      از char به ushort ،int ،uint ،long ،ulong ،float ،double ،decimal
      از float به double

      در مورد انتساب ( مثلاً b = i) همیشه مقدار سمت راست توی مقدار سمت چپ ریخته می‌شه




  3. s0m4y3h
    27 November 2012

    سلام
    لطف ميكنيد سري فيبوناچي رو بنويسيد چطوري ميشه ساخت ؟
    و اعداد مركب رو همين طور
    ممنون ميشم
    جدا
    ببخشيد
    شرمنده




  4. رضا
    11 December 2013

    بسیار سپاسگزارم بابت توضیحات ارزنده شما.




  5. سلام
    10 August 2015

    سلام ببخشید اگر ما short را به byteتبدیل کنیم و عدد ما2200 برای مثال باشد چرا وقتی تبدیل میشه عدد 152 رو چاپ میکنه




  6. hosein
    21 October 2015

    با سلام.
    از اموزش های خوبتون واقعا ممنونم.
    من بیشتر چیز هایی که یاد گرفتم از سایت خوب شما بوده .
    واقعا عالیه




  7. هانا
    15 October 2017

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




  8. حسین بنیادی
    13 December 2017

    سلام مهندس خسته نباشید من یه سوال داشتم من کد زیر رو ک تو آموزش بود رو نوشتم ولی شما گفتید مقدار بایت تا 255 بیشتر تبدیل نمیشه چرا در جواب این کد دقیقا عدد 560 رو نشون میده میشه بگید چه اتفاقی افتاده من یخورده گیج شدم؟
    [css]
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApplication8
    {
    class Program
    {
    static void Main(string[] args)
    {
    int anOkayint = 560;
    byte aBadbyte = (byte)anOkayint;
    Console.WriteLine(anOkayint);

    }
    }
    }

    [css/]



دیدگاه خود را بنویسید





نشانی ایمیل شما منتشر نخواهد شد.

کامنت های شما بعد از تأیید توسط نویسنده وبلاگ، منتشر خواهند شد.

لطفا دیدگاهتان تا حد امکان مربوط به پست بالا باشد. اگر حرف دیگری دارید و یا قصد تماس با من را دارید، از فرم تماس استفاده کنید.

شما میتوانید با مراجعه به سایت گراواتار یک آواتار اختصاصی برای خود تعریف کنید، تا در کنار نام شما نمایش داده شود

برای قرار دادن کدهای نمونه می توانید از تگ های [php] ، [html] ، [css] و [js] استفاده کنید.
به عنوان مثال کدهای php را می توان به صورت زیر قرار داد:
[php] var $whoLoveIranians = "WebTarget!"; [/php]



کلیه حقوق مادی و معنوی برای وب سایت وب تارگت محفوظ است ©2024 وب‌تارگت

استفاده از مطالب وب سایت در سایر وب سایت‌ها و نشریات چاپی با ذکر منبع آزاد است.