آموزش جامع DateTime.TryParse() در C# و .NET با مثالهای عملی
بازگشت به راهنمای جامع متدهای TryParse در سیشارپ؛ این مقاله بهصورت مستقل تمام جنبههای DateTime.TryParse() را از سطح مقدماتی تا نکات حرفهای بررسی میکند.
DateTime.TryParse() برای تبدیل امن رشته به تاریخ و زمان به کار میرود و در سناریوهایی مانند زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم مانع تبدیل خطای قابل انتظار به استثنای کنترلی میشود. طراحی درست فقط فراخوانی متد نیست؛ باید قرارداد ورودی، مرز نوع، فرهنگ، خطای کاربر و اعتبار دامنه نیز مشخص باشد.
دامنه یا قرارداد اصلی این نوع مقادیر معتبر ساختار DateTime همراه با قواعد Culture و DateTimeStyles است. رشتههای تاریخ مبهماند؛ برای قراردادهای ماشینی قالب ISO و برای قالب ثابت TryParseExact مناسبتر است. به همین دلیل نتیجه true صرفاً موفقیت تبدیل نحوی را نشان میدهد و مجاز بودن مقدار برای عملیات جاری باید در مرحله بعد بررسی شود.
قاعده کلیدی: مقدار result را فقط زمانی مصرف کنید که مقدار بازگشتی TryParse برابر true باشد؛ مقدار پیشفرض در مسیر شکست یک داده تأییدشده نیست.
تعریف، امضا و قرارداد خروجی
در الگوی TryParse، ورودی بررسی و نتیجه از طریق پارامتر out برگردانده میشود. در موفقیت، result تاریخ و زمان تفسیرشده را نگه میدارد؛ در شکست مقدار پیشفرض DateTime در آن قرار میگیرد. این قرارداد برای مرزهای غیرقابلاعتماد، مانند فرم و فایل، خوانا است و مسیر شکست را به بخش عادی منطق برنامه تبدیل میکند.
امضاهای مهم
DateTime.TryParse(string? value, out DateTime result);
DateTime.TryParse(string? value, IFormatProvider? provider, DateTimeStyles styles, out DateTime result);
| جزء | نقش | نکته حرفهای |
|---|
| ورودی | رشته یا Span حاوی مقدار | null، قالب و دامنه را بر اساس قرارداد بررسی کنید |
| result | مقدار تبدیلشده | فقط پس از موفقیت معتبر است |
| مقدار بازگشتی | true یا false | مسیر کنترل اصلی اعتبارسنجی است |
| Culture و Style | قواعد تفسیر | در نوعهای حساس صریح تعیین شوند |
تحلیل فنی و طراحی صحیح
استفاده حرفهای از DateTime.TryParse() با تشخیص مرز اعتماد آغاز میشود. متنی که کاربر، فایل CSV، پارامتر URL یا سامانه بیرونی تولید کرده است میتواند خالی، ناسازگار یا مخرب باشد. TryParse یک سد نحوی فراهم میکند، اما طول ورودی، قواعد دامنه، مجوز دسترسی و ارتباط مقدار با سایر فیلدها همچنان باید کنترل شود.
در حوزه زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم باید میان «قابل تبدیل بودن» و «قابل پذیرش بودن» فرق گذاشت. ممکن است متن بهدرستی تبدیل شود اما مقدار خارج از بازه سیاست سازمان، شناسه ناشناخته یا تاریخ غیرمجاز باشد. این جداسازی پیام خطای دقیقتر، آزمون واحد سادهتر و تغییر قواعد کسبوکار بدون دستکاری Parser را ممکن میکند.
در API بهتر است خطای تبدیل به پاسخ ساختیافته شامل نام فیلد و کد خطا تبدیل شود. در Import نیز ردیفهای خراب را همراه شماره خط و دلیل رد در گزارش جدا نگه دارید. حذف خاموش خطاها ممکن است جمع گزارش یا تصمیم مدیریتی را تحریف کند؛ بنابراین شاخص کیفیت داده بخشی از خروجی فرایند است.
Culture باید از قرارداد واقعی داده بیاید. فایل ماشینی معمولاً با InvariantCulture و قالب ثابت امنتر است، درحالیکه فرم محلی باید فرهنگ انتخابشده کاربر را به کار گیرد. اتکا به CurrentCulture سرور میتواند پس از جابهجایی محیط، بهروزرسانی کانتینر یا اجرای تست روی رایانه دیگر نتیجه را تغییر دهد.
از نظر امنیت، DateTime.TryParse() تنها تبدیل را انجام میدهد و جای اعتبارسنجی مجوز، محدودیت طول، Allowlist یا کنترل وجود رکورد را نمیگیرد. برای زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم ورودی بسیار طولانی را پیش از پردازش محدود کنید، اطلاعات حساس را در لاگ ننویسید و پیام داخلی استثنا را مستقیماً به کاربر نشان ندهید.
از نظر نگهداری، بهتر است فراخوانیهای تکراری در Parser یا Value Object دامنهای متمرکز شوند. آن جزء میتواند Culture، بازه مجاز، پیامهای فارسی و انگلیسی و سیاست null را یکسان کند. پراکندگی تبدیل در کنترلر، فرم و Repository معمولاً به رفتارهای متفاوت و رفع اشکال دشوار منجر میشود.
مثالهای عملی گامبهگام
ده مثال زیر از تبدیل پایه آغاز میشوند و به سناریوهای مجموعهداده، null، مرز، خطای Culture و کارایی میرسند. هر مثال برای DateTime.TryParse() طراحی شده و نتیجه نمونه را بدون نیاز به اجرای اولیه نشان میدهد.
مثال شماره 1: تبدیل زمان ISO
قالب ISO برای تبادل ماشینی کمابهام است. Culture و DateTimeStyles صریح مشخص میکنند ورودی دارای Z به UTC تنظیم شود.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string input = "2026-07-23T09:30:00Z";
bool success = DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime value);
Console.WriteLine(success ? value.ToString("O") : "نامعتبر");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| موفقیت | True |
| Kind | Utc |
برای API و پیام رویداد، DateTimeOffset معمولاً Offset را بهتر حفظ میکند؛ انتخاب نوع باید با قرارداد سیستم هماهنگ باشد.
مثال شماره 2: تاریخ با فرهنگ مشخص
رشته 07/23/2026 با فرهنگ en-US تفسیر روشن دارد. همان رشته در فرهنگ دیگر ممکن است نامعتبر یا دارای معنی متفاوت باشد.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string input = "07/23/2026 14:15";
CultureInfo culture = CultureInfo.GetCultureInfo("en-US");
bool ok = DateTime.TryParse(input, culture, DateTimeStyles.None, out DateTime value);
Console.WriteLine(ok ? value.ToString("yyyy-MM-dd HH:mm") : "نامعتبر");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| خروجی | 2026-07-23 14:15 |
فرهنگ ورودی باید بخشی از قرارداد باشد، نه ویژگی تصادفی سرور. برای قالب ثابت از TryParseExact استفاده کنید.
مثال شماره 3: ورود دستهای تاریخ سفارش
چند تاریخ از فایل خوانده میشود و ردیف خراب بدون توقف کل Import گزارش میگردد. این الگو برای پاکسازی داده عملی است.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string[] rows = { "2026-07-23", "bad", "2026-08-01" };
int accepted = 0;
foreach (string input in rows)
{
if (DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
{
accepted++;
Console.WriteLine(date.ToString("yyyy-MM-dd"));
}
}
Console.WriteLine($"accepted={accepted}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| معتبر | 2 |
| نامعتبر | 1 |
شماره ردیف و متن خام را برای رفع خطا نگه دارید، اما داده شخصی را در لاگ عمومی قرار ندهید.
مثال شماره 4: فیلتر مهلتهای آینده
پس از تبدیل، قانون معنایی تاریخ بزرگتر یا مساوی نقطه مبنا اعمال میشود. موفقیت نحوی بهتنهایی معتبر بودن مهلت را تضمین نمیکند.
using System;
using Globalization;
using Linq;
internal static class Program
{
private static void Main()
{
DateTime baseline = new(2026, 7, 23);
string[] raw = { "2026-07-20", "2026-07-25", "invalid" };
var future = raw.Where(text =>
DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date) &&
date >= baseline);
Console.WriteLine(string.Join(", ", future));
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| مهلت پذیرفته | 2026-07-25 |
مقایسه را با TimeZone و تعریف روز کاری هماهنگ کنید. در سامانه چندمنطقهای زمان محلی خام میتواند نتیجه نادرست بدهد.
مثال شماره 5: تبدیل و استانداردسازی UTC
ورودی دارای Offset پس از تبدیل به UTC برای ذخیرهسازی یکنواخت آماده میشود. نمایش به کاربر میتواند بعداً در منطقه زمانی او انجام شود.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string input = "2026-07-23T13:30:00+04:00";
if (DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime value))
{
Console.WriteLine(value.ToUniversalTime().ToString("O"));
}
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| UTC | 2026-07-23T09:30:00.0000000Z |
برای حفظ Offset اصلی از DateTimeOffset استفاده کنید. DateTime در بسیاری از جریانها تنها نقطه زمانی نرمالشده را نگه میدارد.
مثال شماره 6: رفتار با null
مقدار تاریخ اختیاری ممکن است null باشد. TryParse آن را false میکند و مسیر اعتبارسنجی بدون استثنا ادامه مییابد.
using System;
internal static class Program
{
private static void Main()
{
string? input = null;
bool ok = DateTime.TryParse(input, out DateTime value);
Console.WriteLine($"ok={ok}; value={value:O}");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| موفقیت | False |
| result | DateTime.MinValue |
DateTime.MinValue ممکن است در دامنه واقعی نیز مقدار فنی داشته باشد؛ بنابراین وضعیت موفقیت را نگه دارید و به sentinel ضمنی تکیه نکنید.
مثال شماره 7: روز نامعتبر در سال غیرکبیسه
ورودی ۲۹ فوریه ۲۰۲۵ از نظر تقویمی معتبر نیست. TryParse شکست را بدون FormatException گزارش میکند.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string input = "2025-02-29";
bool ok = DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime value);
Console.WriteLine(ok);
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| موفقیت | False |
آزمون مرزهای تقویمی، تغییر سال، ساعت تابستانی و پایان ماه برای سامانههای مالی و رزرو ضروری است.
مثال شماره 8: گروهبندی گزارش روزانه
زمانهای معتبر به تاریخ روز تبدیل میشوند و رکورد نامعتبر در شمارش خطا باقی میماند. این نمونه هسته گزارش روزانه را نشان میدهد.
using System;
using Globalization;
using Linq;
internal static class Program
{
private static void Main()
{
string[] raw = { "2026-07-23 08:00", "2026-07-23 12:00", "bad" };
var dates = raw
.Select(text => DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime value) ? value : (DateTime?)null)
.Where(value => value.HasValue)
.GroupBy(value => value!.Value.Date);
foreach (var group in dates)
{
Console.WriteLine($"{group.Key:yyyy-MM-dd}: {group.Count()}");
}
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| 2026-07-23 | 2 رکورد |
در گزارش سازمانی منطقه زمانی مرجع را قبل از استخراج Date تعیین کنید؛ وگرنه رکورد نزدیک نیمهشب ممکن است در روز اشتباه قرار گیرد.
مثال شماره 9: فرهنگ مبهم و اصلاح آن
رشته 03/04/2026 میتواند سوم آوریل یا چهارم مارس باشد. تعیین en-GB معنی را صریح میکند، ولی قرارداد ماشینی ISO بهتر است.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
string input = "03/04/2026";
CultureInfo british = CultureInfo.GetCultureInfo("en-GB");
DateTime.TryParse(input, british, DateTimeStyles.None, out DateTime value);
Console.WriteLine(value.ToString("yyyy-MM-dd"));
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| تفسیر en-GB | 2026-04-03 |
نمایش تاریخ به زبان کاربر با دریافت تاریخ از API یک مسئله نیست. در مرز سیستم از قالب پایدار استفاده کنید و فقط در UI بومیسازی انجام دهید.
مثال شماره 10: Span در Parser فایل
توکن تاریخ از یک خط بزرگ بدون substring جدا میشود و مستقیماً به overload مبتنی بر ReadOnlySpan داده میشود.
using System;
using Globalization;
internal static class Program
{
private static void Main()
{
ReadOnlySpan<char> token = "2026-07-23".AsSpan();
bool ok = DateTime.TryParse(token, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date);
Console.WriteLine(ok ? date.ToString("yyyy-MM-dd") : "نامعتبر");
}
}
| شاخص خروجی | نتیجه نمونه |
|---|
| خروجی | 2026-07-23 |
برای فرمت کاملاً ثابت، TryParseExact روی Span هم دقت قرارداد و هم کنترل بیشتری فراهم میکند. بهینهسازی باید با Benchmark اثبات شود.
خطاهای رایج و راه اصلاح
- استفاده از result بدون بررسی مقدار بازگشتی؛ اصلاح: منطق مصرف مقدار را داخل شاخه موفقیت قرار دهید.
- یکی گرفتن مقدار پیشفرض با شکست؛ اصلاح: وضعیت تبدیل را همراه مقدار نگه دارید یا Result صریح بسازید.
- اتکا به فرهنگ سرور؛ اصلاح: Culture و Style را از قرارداد داده تعیین کنید.
- پذیرش هر مقدار قابل تبدیل؛ اصلاح: پس از تبدیل، بازه، Allowlist و قواعد ارتباطی دامنه را بررسی کنید.
- حذف خاموش رکورد خراب در Import؛ اصلاح: شمارش و گزارش خطا را در خروجی فرایند قرار دهید.
- نادیده گرفتن نکته اختصاصی نوع؛ اصلاح: رشتههای تاریخ مبهماند؛ برای قراردادهای ماشینی قالب ISO و برای قالب ثابت TryParseExact مناسبتر است.
پیام خطا باید قابل اقدام باشد. بهجای «ورودی نامعتبر است» میتوان قالب مورد انتظار، محدوده مجاز و یک نمونه صحیح را ارائه کرد. بااینحال جزئیات داخلی، Stack Trace یا داده حساس نباید در پاسخ عمومی ظاهر شود.
کارایی، تخصیص حافظه و Best Practice
TryParse برای شکست قابل انتظار از الگوی Parse همراه try/catch مناسبتر است، زیرا استثنا برای کنترل جریان عادی طراحی نشده است. این حکم به معنی ممنوع بودن Parse نیست؛ اگر رشته یک ثابت داخلی معتبر است و خرابی آن باگ برنامه محسوب میشود، fail-fast با Parse میتواند انتخاب روشنی باشد.
overloadهای ReadOnlySpan در Parserهای پرتکرار امکان کار روی برشی از بافر را بدون ساخت substring میدهند. سود آن در فایلهای بزرگ، پروتکل یا پردازش میلیونها توکن بیشتر است. در فرم عادی، پیچیدگی اضافی ممکن است ارزش نداشته باشد؛ ابتدا CPU، Allocation و نرخ شکست را اندازهگیری کنید.
برای آزمون، حداقل حالتهای معتبر، null، خالی، فاصله، Culture متفاوت، کمینه، بیشینه، خارج از محدوده و مقدار معتبر ولی غیرمجاز را پوشش دهید. تستها باید Target Framework واقعی را اجرا کنند، زیرا برخی overloadها و رفتارهای گوشهای میان نسخههای .NET تفاوت دارند.
سؤالات متداول
پرسش 1: DateTime.TryParse() دقیقاً چه مسئلهای را حل میکند؟
DateTime.TryParse() متن را با قرارداد نوع مقصد بررسی میکند و بدون تبدیل شکست قابل انتظار به استثنا، وضعیت موفقیت را برمیگرداند. این ویژگی در ورودی کاربر، فایل، API و تنظیمات ارزشمند است. حوزه رایج این مقاله زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم است، اما اعتبار نحوی فقط نخستین مرحله است و قواعد دامنه باید جدا اعمال شوند.
پرسش 2: در صورت شکست DateTime.TryParse() چه اتفاقی برای result میافتد؟
متد false برمیگرداند و result مقدار پیشفرض نوع را خواهد داشت یا نباید معتبر فرض شود. الگوی درست این است که result فقط در شاخه true مصرف شود. تکیه بر صفر، false، تاریخ کمینه یا Guid.Empty میتواند داده نامعتبر را با یک مقدار واقعی اشتباه بگیرد و خطای خاموش ایجاد کند.
پرسش 3: Culture چه اثری بر DateTime.TryParse() دارد؟
اثر Culture به نوع بستگی دارد. اعداد اعشاری، جداکننده هزارگان و تاریخ به فرهنگ حساساند، درحالیکه Guid و bool قرارداد محدودتری دارند. در مرزهای ماشینی CultureInfo.InvariantCulture و قالب مستند، و در رابط کاربر فرهنگ انتخابشده کاربر مناسب است. فرهنگ سرور نباید بهطور تصادفی نتیجه را تعیین کند.
پرسش 4: چگونه DateTime.TryParse() را در نرمافزار تجاری استفاده کنیم؟
یک لایه اعتبارسنجی بسازید که متن خام، نتیجه تبدیل، کد خطا و پیام قابل فهم را برگرداند. سپس قانون کسبوکار مربوط به زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم را اعمال کنید. این جداسازی هم تستپذیری را بالا میبرد و هم امکان گزارش کیفیت داده، مشاوره فنی و توسعه سفارشی جریان Import را فراهم میکند.
پرسش 5: آیا جایگزینی بهتر از DateTime.TryParse() وجود دارد؟
پاسخ به قرارداد ورودی وابسته است. برای قالب ثابت TryParseExact، برای دادهای که خرابی آن باگ است Parse، و برای تبدیلهای سفارشی یک Value Object یا Parser دامنهای مناسبتر است. هدف انتخاب کوتاهترین کد نیست؛ باید خطا، Culture، سازگاری نسخه و پیام کاربر بهروشنی مدیریت شود.
پرسش 6: برای پیادهسازی سازمانی DateTime.TryParse() چه خدماتی لازم میشود؟
در پروژه بزرگ معمولاً طراحی قرارداد داده، اعتبارسنجی چندلایه، تست مرزی، ثبت خطای امن، داشبورد کیفیت ورودی و پایش لازم است. تیم توسعه یا مشاور میتواند این اجزا را متناسب با معماری C# و .NET، حجم داده و الزامات امنیتی پیاده کند. خود متد کوچک است، اما فرایند قابل اعتماد پیرامون آن اهمیت اصلی را دارد.
پرسش 7: خطای رایج هنگام کار با DateTime.TryParse() چیست؟
رایجترین خطا استفاده از result بدون بررسی مقدار بازگشتی است. خطاهای دیگر شامل اتکا به Culture جاری، نادیده گرفتن مرز نوع، یکی گرفتن اعتبار نحوی و معنایی و حذف خاموش رکورد نامعتبر است. نکته اختصاصی این موضوع نیز چنین است: رشتههای تاریخ مبهماند؛ برای قراردادهای ماشینی قالب ISO و برای قالب ثابت TryParseExact مناسبتر است.
پرسش 8: کارایی DateTime.TryParse() در پردازش حجیم چگونه است؟
در شکستهای قابل انتظار، TryParse معمولاً از کنترل جریان با exception مناسبتر است. overloadهای ReadOnlySpan میتوانند تخصیص substring را کاهش دهند. بااینحال نتیجه به نسخه .NET، الگوی داده و مسیر اجرا وابسته است؛ پروفایلر و BenchmarkDotNet باید تصمیم را تأیید کنند و بهینهسازی زودهنگام نباید خوانایی را قربانی کند.
پرسش 9: بهترین روش طراحی با DateTime.TryParse() چیست؟
قرارداد ورودی را مستند کنید، Culture و Style را در صورت نیاز صریح بدهید، result را فقط پس از true مصرف کنید، اعتبار دامنه را جدا بسنجید و خطا را با پیام قابل اقدام گزارش دهید. برای زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم آزمونهای مرزی، null، مقدار نامعتبر، ورودی بسیار بزرگ و سناریوی واقعی کسبوکار را در مجموعه تست قرار دهید.
پرسش 10: DateTime.TryParse() با کدام نسخههای C# و .NET سازگار است؟
overload پایه string در نسخههای قدیمی .NET نیز در دسترس است، اما overloadهای Span، UTF-8 و رابطهای Generic Math در نسخههای جدیدتر افزوده شدهاند. پروژه باید مستندات Target Framework خود را مبنا قرار دهد. اگر کتابخانه چندهدفه است، API سطح مشترک را انتخاب یا برای نسخههای جدید مسیر بهینه جدا تعریف کنید.
سؤالات مصاحبه C# و .NET
پرسشهای زیر دانش قراردادی و معماری داوطلب را میسنجند، نه صرفاً حفظ کردن امضای متد.
- تفاوت قرارداد خطای DateTime.TryParse() با Parse را توضیح دهید و برای هر کدام یک سناریو نام ببرید.
- چرا بررسی مقدار بازگشتی قبل از result ضروری است و مقدار پیشفرض چه خطری دارد؟
- اثر Culture، Style یا قالب ورودی بر DateTime.TryParse() را با یک مثال تشریح کنید.
- اعتبار نحوی و اعتبار کسبوکار در موضوع زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم چگونه از هم جدا میشوند؟
- چه زمانی overload مبتنی بر ReadOnlySpan ارزشمند است و چگونه سود آن را اندازه میگیرید؟
چکلیست نهایی
- نوع مقصد و محدوده آن با دامنه واقعی داده سازگار است.
- Culture، Style یا قالب ثابت در مرز سیستم مشخص شده است.
- result فقط در مسیر موفقیت مصرف میشود.
- اعتبار نحوی از قواعد کسبوکار جداست.
- null، مقدار خالی، مرز و ورودی خراب تست شدهاند.
- خطاها قابل پایشاند و داده حساس در لاگ قرار نمیگیرد.
- بهینهسازی Span تنها پس از اندازهگیری انجام شده است.
جمعبندی
DateTime.TryParse() ابزار کوچکی برای ساخت مرز ورودی قابل اعتماد است. ارزش واقعی آن زمانی دیده میشود که قرارداد فرهنگ، محدوده، گزارش خطا و اعتبار دامنه پیرامونش درست طراحی شود. در زمان ثبت سفارش، مهلت پرداخت، تاریخ گزارش و ورودی تقویم همین رویکرد از داده خاموش اشتباه، استثناهای پرتکرار و اختلاف رفتار محیطها جلوگیری میکند.
برای مرور سایر نوعها و انتخاب API مناسب، راهنمای جامع همه متدهای TryParse در C# و .NET را مطالعه کنید.