Enum.TryParse() برای تبدیل رشته به مقدار Enum به کار میرود و در سناریوهایی مانند وضعیت سفارش، سطح دسترسی، نوع عملیات و گزینههای محدود دامنه مانع تبدیل خطای قابل انتظار به استثنای کنترلی میشود. طراحی درست فقط فراخوانی متد نیست؛ باید قرارداد ورودی، مرز نوع، فرهنگ، خطای کاربر و اعتبار دامنه نیز مشخص باشد.
دامنه یا قرارداد اصلی این نوع نام عضو، مقدار عددی زیرین و ترکیب نامها برای Enumهای Flags است. یک عدد خارج از اعضای تعریفشده ممکن است تبدیل شود؛ پس در ورودی غیرقابلاعتماد Enum.IsDefined یا Allowlist را نیز بررسی کنید. به همین دلیل نتیجه true صرفاً موفقیت تبدیل نحوی را نشان میدهد و مجاز بودن مقدار برای عملیات جاری باید در مرحله بعد بررسی شود.
مثالهای عملی گامبهگام
ده مثال زیر از تبدیل پایه آغاز میشوند و به سناریوهای مجموعهداده، null، مرز، خطای Culture و کارایی میرسند. هر مثال برای Enum.TryParse() طراحی شده و نتیجه نمونه را بدون نیاز به اجرای اولیه نشان میدهد.
مثال شماره 1: تبدیل نام عضو
نام دقیق عضو Enum به مقدار نوعدار تبدیل میشود و شاخه موفقیت برای ادامه جریان سفارش استفاده میگردد.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string input = "Active";
bool ok = Enum.TryParse<OrderStatus>(input, out OrderStatus status);
Console.WriteLine($"ok={ok}; status={status}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| موفقیت | True |
| وضعیت | Active |
نوع Generic از cast و boxing غیرضروری جلوگیری میکند و خوانایی قرارداد را بالا میبرد.
مثال شماره 2: نادیده گرفتن بزرگی حروف
برای ورودی انسانی میتوان ignoreCase را true کرد تا active نیز پذیرفته شود.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string input = "active";
bool ok = Enum.TryParse<OrderStatus>(input, ignoreCase: true, out OrderStatus status);
Console.WriteLine($"{ok}/{status}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| خروجی | True/Active |
در API داخلی ممکن است حساسیت دقیق به حروف برای کشف زودهنگام ناسازگاری مناسبتر باشد.
مثال شماره 3: پردازش دستهای وضعیتها
چند وضعیت واردشده تبدیل و تعداد خطاها گزارش میشوند. کل فایل با یک ردیف خراب متوقف نمیشود.
using System;
using Linq;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string[] raw = { "Pending", "Active", "unknown", "Disabled" };
int accepted = raw.Count(text => Enum.TryParse<OrderStatus>(text, true, out _));
Console.WriteLine($"accepted={accepted}; rejected={raw.Length - accepted}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| معتبر | 3 |
| نامعتبر | 1 |
برای ردیف نامعتبر متن خام و شماره خط را ثبت کنید تا اصلاح منبع داده ممکن باشد.
مثال شماره 4: فیلتر وضعیت مجاز
موفقیت تبدیل با Allowlist کسبوکار ترکیب میشود؛ فقط Pending و Active برای عملیات جاری مجاز هستند.
using System;
using Linq;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string[] raw = { "Pending", "Disabled", "bad" };
OrderStatus[] allowed = { OrderStatus.Pending, OrderStatus.Active };
var accepted = raw.Where(text =>
Enum.TryParse<OrderStatus>(text, true, out OrderStatus status) &&
allowed.Contains(status));
Console.WriteLine(string.Join(", ", accepted));
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| پذیرفته | Pending |
تعریف عضو Enum بهتنهایی به معنی مجاز بودن آن در هر عملیات نیست. مجوز دامنه را جدا کنترل کنید.
مثال شماره 5: ترکیب با switch
پس از تبدیل موفق، switch رفتار مناسب هر وضعیت را انتخاب میکند و مسیر نامعتبر جدا میماند.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string input = "Disabled";
if (Enum.TryParse<OrderStatus>(input, true, out OrderStatus status))
{
string message = status switch
{
OrderStatus.Pending => "در انتظار",
OrderStatus.Active => "فعال",
OrderStatus.Disabled => "غیرفعال",
_ => "ناشناخته"
};
Console.WriteLine(message);
}
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| پیام | غیرفعال |
switch exhaustiveness به نگهداری بهتر هنگام افزودن عضو جدید کمک میکند؛ مسیر پیشفرض را آگاهانه طراحی کنید.
مثال شماره 6: رفتار با null و خالی
هر دو ورودی بدون استثنا false میشوند. مقدار out نباید بدون بررسی وضعیت مصرف شود.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string? first = null;
string second = "";
Console.WriteLine(Enum.TryParse<OrderStatus>(first, out _));
Console.WriteLine(Enum.TryParse<OrderStatus>(second, out _));
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| null | False |
| خالی | False |
اختیاری بودن فیلد را در مدل بیان کنید؛ نبود مقدار و مقدار ناشناخته دو وضعیت متفاوتاند.
مثال شماره 7: عدد تعریفنشده
Enum.TryParse ممکن است عدد 99 را به نوع Enum تبدیل کند، با اینکه عضوی با این مقدار تعریف نشده است. Enum.IsDefined مرحله معنایی را تکمیل میکند.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
string input = "99";
bool parsed = Enum.TryParse<OrderStatus>(input, out OrderStatus status);
bool defined = parsed && Enum.IsDefined(status);
Console.WriteLine($"parsed={parsed}; defined={defined}; raw={(int)status}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| تبدیل نحوی | True |
| عضو تعریفشده | False |
برای ورودی غیرقابلاعتماد کنترل IsDefined یا Allowlist ضروری است. برای Flags منطق اعتبار متفاوت است.
مثال شماره 8: Enum دارای Flags
نامهای ترکیبی برای Enum پرچمی تبدیل میشوند و سپس HasFlag یا عملگر بیتی قابل استفاده است.
using System;
internal static class Program
{
[Flags]
private enum Permission
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
private static void Main()
{
const string input = "Read, Write";
bool ok = Enum.TryParse<Permission>(input, true, out Permission value);
Console.WriteLine($"ok={ok}; value={value}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| موفقیت | True |
| مقدار | Read, Write |
برای Flags باید بیتهای ناشناخته را با ماسک اعضای مجاز کنترل کنید؛ IsDefined برای ترکیبهای معتبر همیشه راهحل کافی نیست.
مثال شماره 9: Helper جنریک قابل استفاده مجدد
یک تابع جنریک تبدیل و IsDefined را در یک قرارداد واحد جمع میکند تا سرویسها رفتار یکسان داشته باشند.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static TEnum? ParseDefined<TEnum>(string? text)
where TEnum : struct, Enum
{
return Enum.TryParse<TEnum>(text, true, out TEnum value) &&
Enum.IsDefined(value)
? value
: null;
}
private static void Main()
{
Console.WriteLine(ParseDefined<OrderStatus>("Active"));
Console.WriteLine(ParseDefined<OrderStatus>("99"));
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| Active | Active |
| 99 | null |
Helper مشترک باید با سیاست هر دامنه هماهنگ باشد؛ برای Flags یا aliasهای مجاز نسخه جدا بسازید.
مثال شماره 10: استفاده از ReadOnlySpan
توکن وضعیت از بافر بزرگ بدون substring به overload مبتنی بر Span داده میشود.
using System;
internal static class Program
{
private enum OrderStatus
{
Pending = 1,
Active = 2,
Disabled = 3
}
private static void Main()
{
ReadOnlySpan<char> token = "Pending".AsSpan();
bool ok = Enum.TryParse<OrderStatus>(token, true, out OrderStatus status);
Console.WriteLine($"{ok}/{status}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| خروجی | True/Pending |
در Parser حجیم مفید است. سازگاری نسخه هدف را بررسی کنید، زیرا overloadهای Span در چارچوبهای قدیمی موجود نیستند.
سؤالات متداول
پرسش 1: Enum.TryParse() دقیقاً چه مسئلهای را حل میکند؟
Enum.TryParse() متن را با قرارداد نوع مقصد بررسی میکند و بدون تبدیل شکست قابل انتظار به استثنا، وضعیت موفقیت را برمیگرداند. این ویژگی در ورودی کاربر، فایل، API و تنظیمات ارزشمند است. حوزه رایج این مقاله وضعیت سفارش، سطح دسترسی، نوع عملیات و گزینههای محدود دامنه است، اما اعتبار نحوی فقط نخستین مرحله است و قواعد دامنه باید جدا اعمال شوند.
پرسش 2: در صورت شکست Enum.TryParse() چه اتفاقی برای result میافتد؟
متد false برمیگرداند و result مقدار پیشفرض نوع را خواهد داشت یا نباید معتبر فرض شود. الگوی درست این است که result فقط در شاخه true مصرف شود. تکیه بر صفر، false، تاریخ کمینه یا Guid.Empty میتواند داده نامعتبر را با یک مقدار واقعی اشتباه بگیرد و خطای خاموش ایجاد کند.
پرسش 3: Culture چه اثری بر Enum.TryParse() دارد؟
اثر Culture به نوع بستگی دارد. اعداد اعشاری، جداکننده هزارگان و تاریخ به فرهنگ حساساند، درحالیکه Guid و bool قرارداد محدودتری دارند. در مرزهای ماشینی CultureInfo.InvariantCulture و قالب مستند، و در رابط کاربر فرهنگ انتخابشده کاربر مناسب است. فرهنگ سرور نباید بهطور تصادفی نتیجه را تعیین کند.
پرسش 4: چگونه Enum.TryParse() را در نرمافزار تجاری استفاده کنیم؟
یک لایه اعتبارسنجی بسازید که متن خام، نتیجه تبدیل، کد خطا و پیام قابل فهم را برگرداند. سپس قانون کسبوکار مربوط به وضعیت سفارش، سطح دسترسی، نوع عملیات و گزینههای محدود دامنه را اعمال کنید. این جداسازی هم تستپذیری را بالا میبرد و هم امکان گزارش کیفیت داده، مشاوره فنی و توسعه سفارشی جریان Import را فراهم میکند.
پرسش 5: آیا جایگزینی بهتر از Enum.TryParse() وجود دارد؟
پاسخ به قرارداد ورودی وابسته است. برای قالب ثابت TryParseExact، برای دادهای که خرابی آن باگ است Parse، و برای تبدیلهای سفارشی یک Value Object یا Parser دامنهای مناسبتر است. هدف انتخاب کوتاهترین کد نیست؛ باید خطا، Culture، سازگاری نسخه و پیام کاربر بهروشنی مدیریت شود.
پرسش 6: برای پیادهسازی سازمانی Enum.TryParse() چه خدماتی لازم میشود؟
در پروژه بزرگ معمولاً طراحی قرارداد داده، اعتبارسنجی چندلایه، تست مرزی، ثبت خطای امن، داشبورد کیفیت ورودی و پایش لازم است. تیم توسعه یا مشاور میتواند این اجزا را متناسب با معماری C# و .NET، حجم داده و الزامات امنیتی پیاده کند. خود متد کوچک است، اما فرایند قابل اعتماد پیرامون آن اهمیت اصلی را دارد.
پرسش 7: خطای رایج هنگام کار با Enum.TryParse() چیست؟
رایجترین خطا استفاده از result بدون بررسی مقدار بازگشتی است. خطاهای دیگر شامل اتکا به Culture جاری، نادیده گرفتن مرز نوع، یکی گرفتن اعتبار نحوی و معنایی و حذف خاموش رکورد نامعتبر است. نکته اختصاصی این موضوع نیز چنین است: یک عدد خارج از اعضای تعریفشده ممکن است تبدیل شود؛ پس در ورودی غیرقابلاعتماد Enum.IsDefined یا Allowlist را نیز بررسی کنید.
پرسش 8: کارایی Enum.TryParse() در پردازش حجیم چگونه است؟
در شکستهای قابل انتظار، TryParse معمولاً از کنترل جریان با exception مناسبتر است. overloadهای ReadOnlySpan میتوانند تخصیص substring را کاهش دهند. بااینحال نتیجه به نسخه .NET، الگوی داده و مسیر اجرا وابسته است؛ پروفایلر و BenchmarkDotNet باید تصمیم را تأیید کنند و بهینهسازی زودهنگام نباید خوانایی را قربانی کند.
پرسش 9: بهترین روش طراحی با Enum.TryParse() چیست؟
قرارداد ورودی را مستند کنید، Culture و Style را در صورت نیاز صریح بدهید، result را فقط پس از true مصرف کنید، اعتبار دامنه را جدا بسنجید و خطا را با پیام قابل اقدام گزارش دهید. برای وضعیت سفارش، سطح دسترسی، نوع عملیات و گزینههای محدود دامنه آزمونهای مرزی، null، مقدار نامعتبر، ورودی بسیار بزرگ و سناریوی واقعی کسبوکار را در مجموعه تست قرار دهید.
پرسش 10: Enum.TryParse() با کدام نسخههای C# و .NET سازگار است؟
overload پایه string در نسخههای قدیمی .NET نیز در دسترس است، اما overloadهای Span، UTF-8 و رابطهای Generic Math در نسخههای جدیدتر افزوده شدهاند. پروژه باید مستندات Target Framework خود را مبنا قرار دهد. اگر کتابخانه چندهدفه است، API سطح مشترک را انتخاب یا برای نسخههای جدید مسیر بهینه جدا تعریف کنید.