using static System.FormattableString; var number = 11; var text = Invariant($"{number}");
در چه برنامههایی استفاده از بانکهای اطلاعاتی NoSQL مناسبتر است؟
1) برنامههای مدیریت محتوا
2) کاتالوگهای محصولات (هر برنامهای با تعدادی شیء و خصوصا متادیتای متغیر)
3) شبکههای اجتماعی
4) Big Data
5) سایر
1) برنامههای مدیریت محتوا
بانکهای اطلاعاتی NoSQL سندگرا، جهت تهیه برنامههای مدیریت محتوا، بسیار مناسب هستند. در این نوع برنامهها، یک سری محتوا که دارای متادیتایی هستند، ذخیره خواهند شد. این متادیتاها مانند نوع، گروه و هر نوع خاصیت دیگری، میتواند باشند. برای ذخیره سازی این نوع اطلاعات، جفتهای key-value بسیار خوب عمل میکنند. همچنین در بانکهای اطلاعاتی سندگرای NoSQL، با استفاده از مفهوم برچسبها، امکان الصاق فایلهای متناظری به اسناد پیش بینی شدهاست. همانطور که در قسمت قبل نیز ذکر شد، در Document stores، نگارشهای قدیمی اسناد نیز حفظ میشوند. به این ترتیب، این خاصیت و توانمندی توکار، امکان دسترسی به نگارشهای مختلف یک محتوای خاص را به سادگی میسر میسازد. به علاوه اکثر Document stores امکان دسترسی به این مستندات را به کمک URLها و REST API، به صورت خودکار فراهم میسازند.
برای نمونه به CouchDB، عنوان Web database نیز داده شده است؛ از این جهت که یک برنامه وب را میتوان داخل بانک اطلاعاتی آن قرار داد. در اینجا منظور از برنامه وب، یک وب سایت قابل دسترسی از طریق URLها است و نه برنامههای سازمانی وب. برای نمونه ساختاری شبیه به برنامه معروف EverNote را میتوان داخل این نوع بانکهای اطلاعاتی به سادگی ایجاد کرد (خود بانک اطلاعاتی تشکیل شده است از یک وب سرور که REST API را پشتیبانی کرده و امکان دسترسی به اسناد را بدون نیاز به کدنویسی اضافهتری، از طریق URLها و HTTP Verbs استاندارد مهیا میکند).
2) کاتالوگهای محصولات
محصولات در یک کاتالوگ، ویژگیهای مشابه یکسان فراوانی دارند؛ اما تعدادی از این محصولات، دارای ویژگیهایی خاص و منحصربفردی نیز میباشند.
مثلا یک شیء محصول را درنظر بگیرید که دارای خواص مشترک و یکسان شماره، نام، توضیحات و قیمت است. اما بعضی از محصولات، بسته به ردهی خاصی که دارند، دارای ویژگیهای خاصی مانند قدرت تفکیک، رنگ، سرعت و غیره نیز هستند که از هر گروه، به گروه دیگری متغیر است.
برای مدیریت یک چنین نیازی، هر دو گروه key-value stores و wide column stores بانکهای اطلاعاتی NoSQL مناسب هستند؛ از این جهت که در یک key-value store نیازی به تعریف هیچ نوع ساختار خاصی، در ابتدای کار نیست و این ساختار میتواند از هر رکورد، به رکورد دیگری متفاوت باشد.
یا برای نمونه، یک برنامه فرم ساز را درنظر بگیرید که هر فرم آن، هر چند دارای یک سری خواص ثابت مانند نام، گروه و امثال آن است، اما هر کدام دارای فیلدهای تشکیل دهنده متفاوتی نیز میباشد. به این ترتیب با استفاده از key-value stores، دیگری نیازی به نگران بودن در مورد نحوه مدیریت اسکیمای متغیر مورد نیاز، نخواهد بود.
3) شبکههای اجتماعی
همانطور که در قسمت قبل نیز بحث شد، نوع خاص Graph databases برای کاربردهای برنامههای شبکههای اجتماعی و ردیابی تغییرات آنها بسیار مفید و کارآ هستند. برای مثال در یک شبکه افراد دارای تعدادی دنبال کننده هستند؛ عضو گروههای مختلف میباشند، در قسمتهای مختلفی نظر و مطلب ارسال میکنند. در اینجا، اشیاء نسبت به یکدیگر روابط مختلفی دارند. با استفاده از Graph databases، تشکیل روابط self-joins و تو در تو و بسیاری از روشهای خاص، مانند روابط many-to-many که در بانکهای اطلاعاتی رابطهای با تمهیدات ویژهای قابل تشکیل هستند، با سهولت بهتری مدیریت خواهند شد.
4) Big Data
الگوریتم MapReduce، برای کار با حجم دادههای عظیم، طراحی شده است و در این بین، بانکهای اطلاعاتی Wide column store (که در قسمت قبل بررسی شدند) و یا حتی Key-value store (مانند Amazon DynamoDB) بیشتر کاربرد دارند. در سناریوهای دادههای عظیم، واژههای Hadoop و Hbase دنیای NoSQL را زیاد خواهید شنید. Hadoop نسخه سورس باز MapReduce گوگل است و Hbase نیز نسخه سورس باز BigTable گوگل میباشد. مفاهیم پایهای Sharding و فایل سیستمهای Append-only (با سرعت بالای نوشتن) نیز به مدیریت BigData کمک میکنند.
در اینجا بحث مهم، خواندن اطلاعات و آنالیز آنها است و نه تهیه برنامههای معروف CRUD. بسیاری از اعمال آماری و ریاضی مورد نیاز بر روی دادههای عظیم، نیازی به اسکیمای از پیش مشخص شده بانکهای اطلاعاتی رابطهای را ندارند و یا در اینجا قابلیتهای نوشتن کوئریهای پیچیده نیز آنچنان مهم نیستند.
5) سایر کاربردها
- هر سیستمی که اطلاعات Log مانند را تولید میکند. منظور از Log، اطلاعاتی است که در حین رخداد خاصی تولید میشوند. عموما مرسوم است که این نوع اطلاعات را در فایلها، بجای بانک اطلاعاتی ذخیره کرد. بنابراین مدیریت این نوع فایلها توسط بانکهای اطلاعاتی NoSQL، قابلیت انجام امور آماری را بر روی آنها سادهتر خواهد ساخت.
- مدیریت اطلاعات برنامههایی مانند سیستمهای EMail.
و در چه برنامههایی استفاده از بانکهای اطلاعاتی رابطهای مناسبتر است؟
اگر تا اینجا به مزایای استفاده از بانکهای اطلاعاتی NoSQL اشاره شد، بدین معنا نیست که بانکهای اطلاعاتی رابطهای، منسوخ شدهاند یا دیگر قدر و قیمتی ندارند. واقعیت این است که هنوز بازه وسیعی از کاربردها را میتوان به کمک بانکهای اطلاعاتی رابطهای بهتر از بانکهای اطلاعاتی NoSQL مدیریت کرد. این کاربردها و مزیتها در 5 گروه عمده خلاصه میشوند:
1) نیاز به تراکنشها
2) اسکیمای پیش فرض
3) برنامههای LOB یا Line of business applications
4) زبانهای کوئری نویسی پیشرفته
5) نیاز به امکانات گزارشگیری پیشرفته
1) نیاز به تراکنشها
در سیستمهای تجاری عمومی، نیاز به پیاده سازی مفهوم ACID که در قسمتهای قبل به آن پرداخته شد، مانند Atomic transactions وجود دارد. Atomic transaction به زبان ساده به این معنا است که سیستم قادر است چندین دستور را در قالب یک گروه و در طی یک مرحله، به بانک اطلاعاتی اعمال کند و اگر یکی از این دستورات گروه در حال اعمال، با شکست مواجه شد، باید کل تراکنش برگشت خورده و امنیت کار تضمین گردد. در غیراینصورت با یک سیستم غیر هماهنگ مواجه خواهیم شد.
و همانطور که پیشتر نیز عنوان شد، سیستمهای NoSQL، مبنای کار را بر اساس «عاقبت یک دست شدن» اطلاعات قرار دادهاند؛ تا دسترسی پذیری به آنها افزایش یافته و سرعت عملیات به این نحو بهبود یابد. در این نوع سیستمها تضمینی در مورد ACID وجود ندارد.
2) اسکیمای پیش فرض
پروسههای متداول، دارای ساختاری مشخص و معمولی هستند. زیرا طراحی اولیه یک پروسه، بر مبنای مجموعهای از اطلاعات است که همیشه باید وجود داشته باشند و اگر همانند بحث کاتالوگهای محصولات، نیاز به متادیتای متغیر نباشد، ساختار و اسکیمای یک پروسه، از ابتدای طراحی آن مشخص میباشد.
و ... تمام اینها را به خوبی میتوان توسط بانکهای اطلاعاتی رابطهای، با تعریف یک اسکیمای مشخص، مدیریت کرد.
3) برنامههای LOB یا Line of business applications
در برنامههای تجاری متداول، طراحی طرحبندی فرمهای برنامه یا انقیاد دادهها، بر اساس یک اسکیما و ساختار مشخص صورت میگیرد. بدون داشتن یک اسکیمای مشخص، امکان تعاریف انقیاد دادهها به صورت strongly typed وجود نخواهد داشت. همچنین کل مفهوم Object relational mapping و ORMهای مختلف نیز بر اساس وجود یک اسکیمای مشخص و از پیش تعیین شده کار میکند. بنابراین بانکهای اطلاعاتی رابطهای، انتخاب بسیار مناسبی برای تهیه برنامههای تجاری روزمره هستند.
4) زبانهای کوئری نویسی پیشرفته
همانطور که عنوان شد برای تهیه کوئری بر روی اغلب بانکهای اطلاعاتی NoSQL، باید توسط یک برنامه ثانویه، کار پیاده سازی الگوریتم Map Reduce را انجام داد. هر چند تعدادی از این نوع بانکهای اطلاعاتی به صورت توکار دارای موتور MapReduce هستند، اما بسیاری از آنها خیر. به همین جهت برای تهیه کوئریهای متداول، کار پیاده سازی این برنامههای ثانویه مشکل خواهد بود. به این ترتیب نوشتن Ad Hoc queries و گزارشگیری بسیار مشکل میشوند.
علاوه بر امکانات خوب کوئری گرفتن در بانکهای اطلاعاتی رابطهای، این کوئریها در زمان اجرا نیز بر اساس اسکیمای موجود، بسیار بهینه و با سرعت بالا اجرا میشوند. قابلیتی که رسیدن به آن در بانکهای اطلاعاتی با اسکیمای متغیر، کار سادهای نیست و باید آنرا با کدنویسی شخصی بهینه کرد. البته اگر تعداد این نوع برنامههای ثانویه که به آنها imperative query در مقابل declarative query بانکهای رابطهای میگویند، کم باشد، شاید یکبار نوشتن و بارها استفاده کردن از آنها اهمیتی نداشته باشد؛ در غیراینصورت تبدیل به یک عذاب خواهد شد.
5) نیاز به امکانات گزارشگیری پیشرفته
گزارشگیرهای برنامههای تجاری نیز بر اساس یک ساختار و اسکیمای مشخص به کمک قابلیتهای پیشرفته کوئری نویسی بانکهای اطلاعاتی رابطهای به سادگی قابل تهیه هستند. برای تهیه گزارشاتی که قابلیت چاپ مناسبی را داشته باشند، محل قرارگیری فیلدهای مختلف در صفحه مهم هستند و با متغیر بودن آنها، قابلیت طراحی از پیش آنها را از دست خواهیم داد. در این حالت با اسکیمای متغیر، حداکثر بتوان یک dump از اطلاعات را به صورت ستونی نمایش داد.
بنابراین به صورت خلاصه، بانکهای اطلاعاتی رابطهای، جهت مدیریت کارهای روزمره تجاری اغلب شرکتها، بسیار ضروری و جزو مسایل پایهای بهشمار میروند و به این زودیها هم قرار نیست با نمونهی دیگری جایگزین شوند.
tesseract-ocr، یک OCR سورس باز توسعه یافته توسط شرکت HP در بین سالهای 1985 تا 1995 است و اکنون شرکت گوگل کار نگهداری و توسعه آنرا به عهده دارد. کیفیت نویسه خوانی انگلیسی آن فوقالعاده بالا است. در آخرین نگارش آن پشتیبانی از زبان عربی هم را اضافه کرده است.
برای نصب آن ابتدا نگارش قابل حمل آنرا دریافت و سپس فایلهای مرتبط با زبان عربی را نیز باید دریافت کنید. پس از دریافت ایندو، فایلهای زبان عربی را در پوشه tessdata کپی کنید.
کار کردن با آن هم به سادگی اجرای فرمان زیر است:
tesseract.exe image.tif file -l ara
پارامتر اول نام تصویر، پارامتر دوم نام فایل متنی خروجی است (خودش یک txt را به صورت خودکار به فایل تولیدی اضافه میکند) و در آخر زبان عربی مشخص شده است.
برای نمونه تصویر زیر را
به صورت متن زیر نویسه خوانی کرد:
فعلا ابزاری را برای ویرایش فایلهای مرتبط با تشخیص زبان عربی ارائه ندادهاند. بنابراین برای استفاده از آن جهت تشخیص متون فارسی مشکل وجود دارد چون «گچ پژ» را نمیتواند تشخیص دهد و به اینجا که میرسد کلا سیستمش به هم میریزد.
انجمن پرسش و پاسخ آن هم در اینجا قرار دارد.
فایلهای اجرایی و زبان عربی این برنامه را از آدرسهای زیر هم میتوان دریافت کرد:
Mirror: tesseract-ocr-3.01-win32-portable.zip & tesseract-ocr-3.01.ara.tar.gz
گوگل اجازهی فعال کردن POP3 را روی اکانتها GMail میدهد. فرض کنید با استفاده از یکی از کلاینتهای POP3 دات نت میخواهیم ایمیلها را با برنامه نویسی دریافت کنیم (و مثلا از Outlook استفاده نکنیم). اکنون به نظر شما عنوان دریافت شده زیر چه معنایی دارد؟
=?UTF-8?B?QW5hbHl0aWNzIHZhaGlkbmFzaXJpLmJsb2dzcG90LmNvbSAyMDA4MTIyNiAo2KLZhdin?= =?UTF-8?B?2LEg2LPYp9mK2Kop?=
برای درک اتفاق رخ داده باید به RFC های مربوطه مراجعه کرد (RFC-2822 و RFC-2047). مطابق استانداردهای ذکر شده، هدر ارسالی یک ایمیل همواره باید از حروف اسکی تشکیل شود. حال اگر عنوان ایمیل که جزئی از هدر را تشکیل میدهد از حروف غیر اسکی تشکیل شد، حتما باید یک لایه encoding روی آنها صورت گیرد. دو حالت تعریف شده در اینجا مطابق استاندارد میسر است:
الف) Quoted Printable : در این حالت عنوان با =?utf-8?Q شروع میشود.
ب) Base64 : در این روش عنوان با =?utf-8?B شروع خواهد شد.
روش متداول، روش ب است که نسبت به روش الف فشردهتر میباشد. در این حالت برای درک معنای قسمتهای مختلف رشته دریافت شده باید به الگوی زیر مراجعه کرد:
=?charset?encoding?EncodedText?=
در رشته طولانی فوق که در ابتدای مقاله به آن اشاره شده، عنوان به دو قسمت تجزیه شده. یا به عبارتی دوبار الگوی فوق در آن تکرار شده است که باید EncodedText های آنها را یافت و سپس آنها را با توجه به charset مربوطه از حالت base64 به یک رشته معمولی تبدیل نمود.
//using System.Text;
public static string Base64ToString(string charset, string encodedString)
{
//تبدیل بیس 64 به آرایهای از بایتها
byte[] buffer = Convert.FromBase64String(encodedString);
//تبدیل آرایهای از بایتها به رشته با توجه به انکدینگ مربوطه
return Encoding.GetEncoding(charset).GetString(buffer);
}
string subject = Base64ToString("utf-8", "QW5hbHl0aWNzIHZhaGlkbmFzaXJpLmJsb2dzcG90LmNvbSAyMDA4MTIyNiAo2KLZhdin2LEg2LPYp9mK2Kop");
- Explicit
- Implicit
کامپایلر JIT
همانطور که در تصویر فوق مشاهده میکنید، سورس کد توسط کامپایلر دات نت به exe و یا dll کامپایل میشود. کامپایلر JIT تنها متدهایی را که در زمان اجرا(runtime) فراخوانی میشوند را کامپایل میکند. در دات نت فریم ورک سه نوع JIT Compilation داریم:
Normal JIT Compilation
در این نوع کامپایل، متدها در زمان فراخوانی در زمان اجرا کامپایل میشوند. بعد از اجرا، متد داخل حافظه ذخیره میشود. به متدهای ذخیره شده در حافظه jitted گفته میشود. دیگر نیازی به کامپایل متد jit شده نیست. در فراخوانی بعدی، متد مستقیماً از حافظه کش در دسترس خواهد بود.
Econo JIT Compilation
این نوع کامپایل شبیه به حالت Normal JIT است با این تفاوت که متدها بلافاصله بعد از اجرا از حافظه حذف میشوند.
Pre-JIT Compilation
یکی دیگر از حالتهای کامپایل برنامههای دات نتی Pre-JIT Compilation می باشد. در این حالت به جای متدهای مورد استفاده، کل اسمبلی کامپایل میشود. در دات نت میتوان اینکار را توسط Ngen.exe یا (Native Image Generator) انجام داد. تمام دستورالعملهای CIL قبل از اجرا به کد محلی(Native Code) کامپایل میشوند. در این حالت runtime میتواند از native images به جای کامپایلر JIT استفاده کند. این نوع کامپایل عملیات تولید کد را در زمان اجرای برنامه به زمان Installation منتقل میکند، در اینصورت برنامه نیاز به یک Installer برای اینکار دارد.
Multicore JIT
در دات نت فریم ورک 4.5 یک راه حل جایگزین دیگر برای بهینه سازی و بهبود سرعت اجرای برنامههای دات نت وجود دارد. همانطور که عنوان شد Ngen.exe برای در دسترس بودن نیاز به Installer برای برنامه دارد. توسط Multicore JIT متدها بر روی دو هسته به صورت موازی کامپایل میشوند، در اینصورت میتوانید تا 50 درصد از JIT Time صرفه جویی کنید.
Multicore JIT همچنین میتواند باعث بهبود سرعت در برنامههای WPF شود. در نمودار زیر میتوانید حالتهای استفاده و عدم استفاده از Multicore JIT را در سه برنامه WPF نوشته شده مشاهده کنید.
Multicore JIT در عمل
Multicore JIT از دو مد عملیاتی استفاده میکند: مد ثبت(Recording mode)، مد بازپخش(Playback mode)
در حالت ثبت کامپایلر JIT هر متدی که نیاز به کامپایل داشته باشد را رکورد میکند. بعد از اینکه CLR تعیین کند که اجرای برنامه به اتمام رسیده است، تمام متدهایی که اجرا شده اند را به صورت یک پروفایل بر روی دیسک ذخیره میکند.
هنگامیکه Multicore JIT فعال میشود، با اولین اجرای برنامه، حالت ثبت مورد استفاده قرار میگیرد. در اجراهای بعدی، از حالت بازپخش استفاده میشود. حالت بازپخش پروفایل را از طریق دیسک بارگیری کرده، و قبل از اینکه این اطلاعات توسط ترد اصلی مورد استفاده قرار گیرد، از آنها برای تفسیر (کامپایل) متدها در پیشزمینه استفاده میکند.
در نتیجه، ترد اصلی به کامپایل دیگری نیاز ندارد، در این حالت سرعت اجرای برنامه بیشتر میشود. حالتهای ثبت و بازپخش تنها برای کامپیوترهایی با چندین هسته فعال میباشند.
استفاده از Multicore JIT
در برنامههای 4.5 ASP.NET و 5 Silverlight به صورت پیش فرض این ویژگی فعال میباشد. ازآنجائیکه این برنامهها hosted application هستند؛ در نتیجه فضای مناسبی برای ذخیره سازی پروفایل در این نوع برنامهها موجود میباشد. اما برای برنامههای Desktop این ویژگی باید فعال شود. برای اینکار کافی است دو خط زیر را به نقطه شروع برنامه تان اضافه کنید:
public App() { ProfileOptimization.SetProfileRoot(@"C:\MyAppFolder"); ProfileOptimization.StartProfile("Startup.Profile"); }
توسط متد SetProfileRoot میتوانیم مسیر ذخیره سازی پروفایل JIT را مشخص کنیم. در خط بعدی نیز توسط متد StartProfile نام پروفایل را برای فعال سازی Multicore JIT تعیین میکنیم. در این حالت در اولین اجرای برنامه پروفایلی وجود ندارد، Multicore JIT در حالت ثبت عمل میکند و پروفایل را در مسیر تعیین شده ایجاد میکند. در دومین بار اجرای برنامه CRL پروفایل را از اجرای قبلی برنامه بارگذاری میکند؛ در این حالت Multicore JIT به صورت بازپخش عمل میکند.
همانطور که عنوان شد در برنامههای ASP.NET 4.5 و Silverlight 5 قابلیت Multicore JIT به صورت پیش فرض فعال میباشد. برای غیر فعال سازی آن میتوانید با تغییر فلگ profileGuidedOptimizations به None اینکار را انجام دهید:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- ... --> <system.web> <compilation profileGuidedOptimizations="None" /> <!-- ... --> </system.web> </configuration>
آشنایی با PowerShell 7x
- قسمت اول - معرفی و نصب
- قسمت دوم - آشنایی با Pipelineها
- قسمت سوم - آشنایی با Redirection
- قسمت چهارم - نوشتن اولین اسکریپت
- قسمت پنجم - اسکریپت بلاک و توابع
- قسمت ششم - ایجاد Cmdletها توسط #C
- قسمت هفتم - غنیسازی PowerShell
- قسمت هشتم - ماژولها
- قسمت نهم - آشنایی با Crescendo
- قسمت دهم - بررسی مشکلات به همراه پرچم فرمت
- قسمت یازدهم - یک مثال
- قسمت دوازدهم - آشنایی با GitHub Actions و بررسی یک مثال
- قسمت سیزدهم - ساخت یک Static Site Generator ساده توسط PowerShell و GitHub Actions
دوره 3 ساعته NET MAUI.
.NET MAUI Course for Beginners – Create Cross-Platform Apps with C#
Learn how to use .NET MAUI for native cross-platform desktop and mobile development! You will learn the essentials of building mobile applications with .NET MAUI and C# while creating a Contacts app.
⭐️ Contents ⭐️
⌨️ (0:00:00) Introduction
⌨️ (0:03:42) What is .Net Maui - .Net Maui vs Xamarin Forms
⌨️ (0:06:52) Prepare Development Environment _ Create first project
⌨️ (0:12:29) Project Structure
⌨️ (0:20:28) Three elements of stateful .Net Maui
⌨️ (0:23:51) Page, Layout _ View, Namespaces
⌨️ (0:33:02) URL based navigation
⌨️ (0:51:10) Basics of ListView and Data Binding
⌨️ (1:05:58) Events Handling of ListView
⌨️ (1:16:54) Parameters in URL based Navigation _ Static Repository
⌨️ (1:35:35) Stacklayout for Edit Contact page
⌨️ (1:52:47) View Contact Details _ Update Contact
⌨️ (2:06:40) Observable Collection
⌨️ (2:14:58) Field Validation with .Net Maui CommunityToolkit
⌨️ (2:27:08) Reusable Control
⌨️ (2:40:37) Grid Layout and Use reusable control
⌨️ (2:53:23) ContextActions _ MenuItems in ListView
⌨️ (3:03:44) SearchBar in .NetMaui
«از این پس حین استفاده از انواع و اقسام لیستها، آرایهها، IEnumerableها و امثال آنها، جهت بررسی خالی بودن یا نبودن آنها تنها از متد Any فراهم شده توسط LINQ استفاده نمائید.»
اکنون پس از سالها، قصد داریم صحت این مساله را با NET 5.0. بررسی کنیم که آیا هنوز هم متد Any، بهترین متد بررسی خالی بودن مجموعهها و آرایههای NET 5.0. است یا خیر؟
نحوهی بررسی کارآیی روشهای مختلف خالی بودن مجموعهها و آرایهها در C# 9.0
در ابتدا یک لیست، یک Enumerable و یک آرایه را به صورت زیر مقدار دهی میکنیم و هر سهی اینها میتوانند نال هم باشند:
private IList<int>? _idsList; private IEnumerable<int>? _idsEnumerable; private int[]? _idsArray; [GlobalSetup] public void Setup() { _idsEnumerable = Enumerable.Range(0, 10000); _idsList = _idsEnumerable.ToList(); _idsArray = _idsEnumerable.ToArray(); }
اکنون که C# 9.0 در اختیار ما است به همراه pattern matching و همچنین Null Conditional Operator و غیره، میتوان روشهای زیر را برای بررسی خالی بودن این مجموعهها و آرایهها بکار گرفت:
1- استفاده از Null coalescing برای بررسی نال بودن مجموعه و سپس استفاده از متد Any برای بررسی خالی بودن آن:
var list = _idsList ?? new List<int>(); if (list.Any() is false) { }
2- استفاده از pattern matching برای بررسی نال بودن مجموعه و سپس استفاده از متد Any برای بررسی خالی بودن آن:
if (_idsList is null || _idsList.Any() is false) { }
3- استفاده از روش سنتی مقایسهی مستقیم با null و سپس استفاده از متد Any برای بررسی خالی بودن آن:
if (_idsList == null || _idsList.Any() is false) { }
4- استفاده از Null Conditional Operator برای بررسی نال بودن و سپس استفاده از متد Any برای بررسی خالی بودن آن:
if (_idsList?.Any() is false) { }
5- استفاده از pattern matching برای بررسی مقدار خاصیت Count یک لیست یا آرایه. البته Enumerableها به همراه این خاصیت نیستند و یا باید آنها را به لیست و یا آرایه تبدیل کرد و یا میتوان متد ()Count آنها را فراخوانی نمود:
if (_idsList is { Count: > 0 } is false) { }
6- استفاده از Null Conditional Operator برای بررسی نال بودن و سپس استفاده از مقدار خاصیت Count لیست، برای بررسی خالی بودن آن:
if (_idsList?.Count == 0) { }
7- استفاده از روش سنتی مقایسهی مستقیم با null و سپس استفاده از مقدار خاصیت Count لیست، برای بررسی خالی بودن آن:
if (_idsList == null || _idsList.Count == 0) { }
کدهای کامل این بررسی به صورت زیر هستند: AnyCountBenchmark.zip
ابتدا ارجاعی به BenchmarkDotNet به برنامه اضافه شدهاست:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <Nullable>enable</Nullable> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> <ItemGroup> <PackageReference Include="BenchmarkDotNet" Version="0.12.1" /> </ItemGroup> </Project>
و سپس کدهای زیر، بررسی کارآیی روشهای مختلف تعیین خالی بودن مجموعهها را انجام میدهند:
using BenchmarkDotNet.Running; namespace AnyCountBenchmark { public static class Program { static void Main(string[] args) { #if DEBUG System.Console.WriteLine("Please set the project's configuration to Release mode first."); #else BenchmarkRunner.Run<Scenarios>(); #endif } } }
به همراه سناریوهای مختلف زیر:
using System; using System.Collections.Generic; using System.Linq; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Order; namespace AnyCountBenchmark { [SimpleJob(RuntimeMoniker.NetCoreApp50)] [Orderer(SummaryOrderPolicy.FastestToSlowest, MethodOrderPolicy.Declared)] [RankColumn] public class Scenarios { private IList<int>? _idsList; private IEnumerable<int>? _idsEnumerable; private int[]? _idsArray; [GlobalSetup] public void Setup() { _idsEnumerable = Enumerable.Range(0, 10000); _idsList = _idsEnumerable.ToList(); _idsArray = _idsEnumerable.ToArray(); } #region Any_With_Null_coalescing [Benchmark] public void List_Any_With_Null_coalescing() { var list = _idsList ?? new List<int>(); if (list.Any() is false) { } } [Benchmark] public void Array_Any_With_Null_coalescing() { var array = _idsArray ?? Array.Empty<int>(); if (array.Any() is false) { } } [Benchmark] public void Enumerable_Any_With_Null_coalescing() { var enumerable = _idsEnumerable ?? Enumerable.Empty<int>(); if (enumerable.Any() is false) { } } #endregion #region Any_With_Is_Null_Check [Benchmark] public void List_Any_With_Is_Null_Check() { if (_idsList is null || _idsList.Any() is false) { } } [Benchmark] public void Array_Any_With_Is_Null_Check() { if (_idsArray is null || _idsArray.Any() is false) { } } [Benchmark] public void Enumerable_Any_With_Is_Null_Check() { if (_idsEnumerable is null || _idsEnumerable.Any() is false) { } } #endregion #region Any_Any_With_Null_Equality_Check [Benchmark] public void List_Any_With_Null_Equality_Check() { if (_idsList == null || _idsList.Any() is false) { } } [Benchmark] public void Array_Any_With_Null_Equality_Check() { if (_idsArray == null || _idsArray.Any() is false) { } } [Benchmark] public void Enumerable_Any_With_Null_Equality_Check() { if (_idsEnumerable == null || _idsEnumerable.Any() is false) { } } #endregion #region Any_With_Null_Conditional_Operator [Benchmark] public void List_Any_With_Null_Conditional_Operator() { if (_idsList?.Any() is false) { } } [Benchmark] public void Array_Any_With_Null_Conditional_Operator() { if (_idsArray?.Any() is false) { } } [Benchmark] public void Enumerable_Any_With_Null_Conditional_Operator() { if (_idsEnumerable?.Any() is false) { } } #endregion #region Count_With_Pattern_Matching [Benchmark] public void List_Count_With_Pattern_Matching() { if (_idsList is { Count: > 0 } is false) { } } [Benchmark] public void Array_Length_With_Pattern_Matching() { if (_idsArray is { Length: > 0 } is false) { } } [Benchmark] public void Enumerable_Count_With_Pattern_Matching() { var list = _idsEnumerable?.ToList(); if (list is { Count: > 0 } is false) { } } #endregion #region Count_With_Null_Conditional_Operator [Benchmark] public void List_Count_With_Null_Conditional_Operator() { if (_idsList?.Count == 0) { } } [Benchmark] public void Array_Length_With_Null_Conditional_Operator() { if (_idsArray?.Length == 0) { } } [Benchmark] public void Enumerable_Count_With_Null_Conditional_Operator() { if (_idsEnumerable?.Count() == 0) { } } #endregion #region Count_With_Null_Equality_Check [Benchmark] public void List_Count_With_Null_Equality_Check() { if (_idsList == null || _idsList.Count == 0) { } } [Benchmark] public void Array_Length_With_Null_Equality_Check() { if (_idsArray == null || _idsArray.Length == 0) { } } [Benchmark] public void Enumerable_Count_With_Null_Equality_Check() { if (_idsEnumerable == null || _idsEnumerable.Count() == 0) { } } #endregion } }
نتایج حاصل:
- بررسی خالی بودن آرایهها، بسیار سریعتر از بررسی خالی بودن لیستها و این مورد نیز سریعتر از Enumerableها است.
- اگر از آرایهها و یا لیستها استفاده میکنید، بررسی خاصیت Length و یا خاصیت Count آنها، بسیار سریعتر از بکارگیری متد Any بر روی آنها است.
- اگر از Enumerableها استفاده میکنید، استفاده از متد Any بر روی آنها، بسیار سریعتر از بکارگیری متد ()Count و یا تبدیل آنها به لیست و سپس بررسی خاصیت Count آنها است.
- بررسی نال بودن با pattern matching یا همان is null، نسبت به روشی سنتی استفادهی از null ==، سریعتر است. علت آنرا در مطلب «روش ترجیح داده شدهی مقایسه مقادیر اشیاء با null از زمان C# 7.0 به بعد» میتوانید مطالعه کنید.
بنابراین برای بررسی خالی بودن آرایهها و لیستها، بهتر است از خاصیت Length و یا Count آنها استفاده کرد و برای Enumerableها از متد ()Any.