هنر تبدیل دادهها در سیشارپ
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۳/۱۰ ۱۲:۵۷
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
int، decimal و غیره) نیاز به تبدیل به نوع عددی دارد.int به decimal یک تبدیل ضمنی و ایمن محسوب میشود:int num = 10; decimal cost = num; // تبدیل ایمن و ضمنی
int است، به طور خودکار به decimal تبدیل میشود و متغیر cost مقدار 10.0m را میگیرد. استفاده از این روش زمانی توصیه میشود که از تبدیل از یک نوع داده با محدوده کمتر به یک نوع داده با محدوده بیشتر (مانند int به long یا float به double) اطمینان دارید. این نوع تبدیل، کارایی بالایی دارد زیرا نیازی به بررسیهای زمان اجرا ندارد.decimal به int میتواند منجر به از دست رفتن قسمت اعشاری شود:decimal bill = 45.99m; int roundedBill = (int)bill; // قسمت اعشاری را حذف میکند (truncates)
bill که 45.99m است، پس از کستینگ به int، به 45 تبدیل میشود و قسمت 0.99 از بین میرود. از کستینگ زمانی استفاده کنید که از احتمال از دست رفتن دادهها آگاه هستید و این موضوع برای برنامه شما قابل قبول است. این روش نیز مانند تبدیل ضمنی، از نظر کارایی بالا است، زیرا مستقیماً به حافظه دسترسی پیدا میکند و نیازی به سربار اضافی ندارد. با این حال، استفاده نادرست از آن میتواند منجر به نتایج غیرمنتظره و باگ (Bug) شود.TryParse(): ایمنی در برابر ورودی کاربرTryParse() یکی از بهترین و ایمنترین روشها برای تبدیل ورودیهای کاربر است. برخلاف متد Parse()، این متد در صورت نامعتبر بودن ورودی، استثنا (Exception) پرتاب نمیکند و به جای آن، یک مقدار بولی (Boolean) (true یا false) را بازمیگرداند که نشاندهنده موفقیت یا عدم موفقیت تبدیل است. این ویژگی آن را برای رابطهای کاربری (UI) و پردازش ورودی کاربر ایدهآل میسازد.string input = "123";
int result;
if (int.TryParse(input, out result))
{
Console.WriteLine(result); // خروجی: 123
}
else
{
Console.WriteLine("ورودی نامعتبر است.");
}TryParse() بهترین گزینه است. این متد به شما امکان میدهد تا بدون نگرانی از توقف ناگهانی برنامه (crash)، ورودیها را اعتبارسنجی (validate) کنید و در صورت لزوم، پیام مناسبی به کاربر نمایش دهید.Convert: تبدیل با قابلیت گرد کردنConvert مجموعهای از متدهای استاتیک را برای تبدیل انواع دادهها به یکدیگر فراهم میکند. یکی از ویژگیهای بارز این کلاس، گرد کردن (Rounding) مقادیر در حین تبدیل است. به عنوان مثال، متد Convert.ToInt32() هنگام تبدیل یک عدد اعشاری، آن را به نزدیکترین عدد صحیح گرد میکند (قاعده "گرد کردن به نزدیکترین عدد زوج" یا "Banker's Rounding" را دنبال میکند).string value = "12.6"; decimal cost = Convert.ToDecimal(value); // cost = 12.6m int rounded = Convert.ToInt32(cost); // rounds: 12.6 -> 13
12.6m به 13 گرد میشود. استفاده از کلاس Convert زمانی مناسب است که نیاز به رفتار گرد کردن دارید و یا میخواهید از یک رابط (interface) یکپارچه برای تبدیل انواع مختلف داده استفاده کنید. این کلاس برای تبدیلهای عمومی که در آنها گرد کردن قابل قبول است، بسیار مفید است.Console.WriteLine("ساعات را وارد کنید:");
string hoursInput = Console.ReadLine();
Console.WriteLine("نرخ ساعتی را وارد کنید:");
string costInput = Console.ReadLine();
if (decimal.TryParse(hoursInput, out decimal hours) &&
decimal.TryParse(costInput, out decimal rate))
{
decimal total = hours * rate;
Console.WriteLine($"هزینه کل: {total:C2}"); // نمایش با فرمت واحد پول
}
else
{
Console.WriteLine("ورودی نامعتبر است. لطفاً فقط اعداد را وارد کنید.");
}decimal.TryParse() برای هر دو ورودی hoursInput و costInput استفاده شده است. این رویکرد تضمین میکند که اگر کاربر به جای عدد، رشتهای نامعتبر (مثلاً "abc") را وارد کند، برنامه به جای توقف ناگهانی (crash)، یک پیام خطای دوستانه نمایش دهد.TryParse() از Parse() استفاده میکردیم چه اتفاقی میافتاد؟Parse() استفاده میکردیم و کاربر ورودی نامعتبر (مانند "abc") را تایپ میکرد، برنامه با یک استثنا (Exception) از نوع System.FormatException مواجه میشد و متوقف میگشت:System.FormatException: Input string was not in a correct format.
TryParse() برای ورودیهای کاربر ارجحیت دارد. در حالی که Parse() برای دادههای قابل اعتماد و هاردکد شده که از صحت آنها اطمینان دارید مناسب است، استفاده از آن برای ورودیهای غیرقابل پیشبینی میتواند منجر به تجربه کاربری نامناسب و ناپایداری برنامه شود.TryParse() بهترین راه حل برای این مورد است.TryParse() برای محاسبات ایمن و جلوگیری از توقف ناگهانی، نمونه بارز کاربرد صحیح این اصول است. این موضوع تنها به نوشتن کد ختم نمیشود، بلکه به تفکر از دیدگاه کاربر نیز مربوط میشود.| شاخص / روش | TryParse | Parse | Convert.ToType | کستینگ (مثال: (int)) |
| ایمن در استفاده | بله | خیر | بله (در اکثر موارد) | خیر (میتواند منجر به از دست رفتن داده شود) |
| گرد کردن مقادیر | خیر | خیر | بله (مثلاً 2.9 به 3 تبدیل میشود) | خیر (قسمت اعشاری را حذف میکند، مثلاً 3.9 به 3 تبدیل میشود) |
| پرتاب استثنا | خیر | بله | بله | خیر |
| بهترین کاربرد | تبدیل ورودی کاربر که ممکن است نامعتبر باشد. در صورت نامعتبر بودن، true/false باز میگرداند. | تبدیل دادههای قابل اعتماد یا هاردکد شده که از صحت آنها اطمینان دارید. | تبدیلهای عمومی که در آنها گرد کردن قابل قبول است. | کارایی بالا یا زمانی که آگاهانه میخواهید دقت اعشاری را حذف کنید. |
(با نام value) و دومی هم یک مقدار از نوع Number که تعداد دقت اعشار باشه (با نام precision). مثلا اگر عدد 2.2568 رو به همراه دقت اعشار (مثلا 2 عدد) از کاربر دریافت کنه و سپس مقدار اولیه که از نوع decimal بود، خروجی هم decimal برگردونه به شرطی که در هیچ یک از فرآیندهای تبدیل، به رشته تبدیل نکنه. ابتدا کد زیر را پیشنهاد کرد:decimal originalValue = 2.2568m; decimal roundedValue = Math.Round(originalValue, 1, MidpointRounding.AwayFromZero); Console.WriteLine(roundedValue); // Output: 2.3
Truncate رو پیشنهاد داد که باز هم به دلیل اینکه امکان تعیین تعداد اعشار وجود نداشت این کد هم جواب کار نبود:decimal truncatedValue = Math.Truncate(originalValue * 10) / 10; Console.WriteLine(truncatedValue); // Output: 2.2
public static decimal TruncateDecimal(decimal value, int precision)
{
decimal factor = (decimal)Math.Pow(10, precision);
return Math.Truncate(value * factor) / factor;
}decimal originalValue = 2.2568m; decimal truncated1 = TruncateDecimal(originalValue, 1); // Output: 2.2 decimal truncated2 = TruncateDecimal(originalValue, 2); // Output: 2.25 decimal truncated3 = TruncateDecimal(originalValue, 3); // Output: 2.256 Console.WriteLine(truncated1); Console.WriteLine(truncated2); Console.WriteLine(truncated3);
decimal factor = (decimal)Math.Pow(10, precision);
Math.Pow(10, precision): عدد 10 را به اندازه مقدار دقتی که در پارامتر متد دریافت کرده افزایش میدهد (به توان میرساند). این کار کمک میکند تا اعشار به سمت راست جابجا شود:decimal با نام factor ذخیره خواهد شد.value * factor
factor نتیجه بصورت زیر خواهد شد:Math.Truncate(value * factor)
Math.Truncate(value * factor) / factor