نظرات مطالب
پاسخ به این سؤال نیاز به مهندسی معکوس دارد ولی عموما از روشهای متقارن رمزنگاری استفاده میشود
پاسخ به بازخوردهای پروژهها
پر نکردن فیلد های PDF با استفاده از iTextSharp
نظرات مطالب
پیاده سازی اسکرام با شیرپوینت
کاملا با نظرتون در مورد نظریه شیرپوینت و بیکار کردن برنامه نویس ها موافقم، اما یک برنامه نویس ماکروسافت تا جه حد نیاز به دانستن مفاهیم شیر پوینت دارد؟ و آیا مفاهیم کلی، راه اندازی مدیریت، و توسعه شیر پویت با آنجه که ما تا به حال در مورد ماکروسافت و نرم افزار های آن میدانیم خیلی فرق دارد ؟
شاید برایتان تا حالا پیش آمده باشد که بخواهید یکسری کاراکترهای ناخواسته و اضافه را از یک رشته حذف کنید. بطور مثال تمام کاراکتر هایی غیر عددی را باید از یک رشته حذف نمود تا آن رشته قابلیت تبدیل به نوع integer را بدست بیاورد.
اگر تعداد کاراکترهای ناخواسته محدود و مشخص هستند میتوانید با دستور REPLACE آنها را حذف کنید، مثلا میخواهیم هر سه کاراکتر ~!@ از رشته حذف شوند:
ولی هنگامی که کاراکترها نامحدود بوده امکان نوشتن تابع REPLACE به کرات بی معنا است در این حالت باید دنبال روشی پویا و تعمیم پذیر بود.
با جستجویی که در اینترنت انجام دادم متوجه شدم تکنیک WHILE یا همون loop یکی از روشهای رایج برای انجام اینکار هست، که احتمالا به دلیل سهولت در بکارگیری و سادگی آن بوده که عمومیت پیدا کرده است.
مستقل از این صحبتها هدف معرفی یک روش مجموعه گرا (set-based) برای این مساله میباشد.
حذف کاراکترها ناخواسته با تکنیک Recursive CTE
راه حل بر اساس جدول زیر است:
حالا فرض کنید میخواهیم هر کاراکتری غیر از حروف الفبای انگلیسی و فاصله(space) از رشته حذف شود. پس دو داده فوق به صورت salam و good bye در انتها در خواهند آمد.
برای حذف کاراکترهای ناخواسته فوق query زیر را اجرا کنید.
توضیح query:
در قسمت anchor اندیس اولین کاراکتر ناخواسته (خارج از رنج حروف الفبا و فاصله) بدست میآید. سپس در قسمت recursive هر کاراکتری که برابر باشد با کاراکتر ناخواسته ای که در مرحله قبل بدست آمده از رشته حذف میشود این عملیات توسط تابع replace صورت میگیرد و اندیس کاراکتر ناخواسته بعدی بعد از حذف کاراکتر ناخواسته قبلی بدست میآید که به مرحله بعد منتقل میشود. این مراحل تا آنجایی پیش میرود که دیگر کاراکتر ناخواسته ای در رشته وجود نداشته باشد.
به جدول زیر توجه بفرمایید (خروجی query فوق)
اگر تعداد کاراکترهای ناخواسته محدود و مشخص هستند میتوانید با دستور REPLACE آنها را حذف کنید، مثلا میخواهیم هر سه کاراکتر ~!@ از رشته حذف شوند:
DECLARE @s VARCHAR(50) = '~~~~~~!@@@@@@@ salam'; SET @s = REPLACE(REPLACE(REPLACE(@s, '~', ''), '!', ''), '@', ''); SELECT @s AS new_string
ولی هنگامی که کاراکترها نامحدود بوده امکان نوشتن تابع REPLACE به کرات بی معنا است در این حالت باید دنبال روشی پویا و تعمیم پذیر بود.
با جستجویی که در اینترنت انجام دادم متوجه شدم تکنیک WHILE یا همون loop یکی از روشهای رایج برای انجام اینکار هست، که احتمالا به دلیل سهولت در بکارگیری و سادگی آن بوده که عمومیت پیدا کرده است.
مستقل از این صحبتها هدف معرفی یک روش مجموعه گرا (set-based) برای این مساله میباشد.
حذف کاراکترها ناخواسته با تکنیک Recursive CTE
راه حل بر اساس جدول زیر است:
CREATE TABLE test_string (id integer not null primary key, string_value varchar(500) not null); INSERT INTO test_string VALUES (1, '@@@@ #### salam 12345'), (2, 'good $$$$$ &&&&&& bye 00000');
حالا فرض کنید میخواهیم هر کاراکتری غیر از حروف الفبای انگلیسی و فاصله(space) از رشته حذف شود. پس دو داده فوق به صورت salam و good bye در انتها در خواهند آمد.
برای حذف کاراکترهای ناخواسته فوق query زیر را اجرا کنید.
WITH CTE (ID, MyString, Ix) AS ( SELECT id, string_value, PATINDEX('%[^a-z ]%', string_value) FROM test_string UNION ALL SELECT id, CAST(REPLACE(MyString, SUBSTRING(MyString,Ix , 1), '') AS VARCHAR(500)), PATINDEX('%[^a-z ]%', REPLACE(MyString, SUBSTRING(MyString,Ix , 1), '')) FROM CTE WHERE Ix > 0 ) SELECT * FROM cte --WHERE Ix = 0; ORDER BY id, CASE WHEN Ix = 0 THEN 1 ELSE 0 END, Ix;
توضیح query:
در قسمت anchor اندیس اولین کاراکتر ناخواسته (خارج از رنج حروف الفبا و فاصله) بدست میآید. سپس در قسمت recursive هر کاراکتری که برابر باشد با کاراکتر ناخواسته ای که در مرحله قبل بدست آمده از رشته حذف میشود این عملیات توسط تابع replace صورت میگیرد و اندیس کاراکتر ناخواسته بعدی بعد از حذف کاراکتر ناخواسته قبلی بدست میآید که به مرحله بعد منتقل میشود. این مراحل تا آنجایی پیش میرود که دیگر کاراکتر ناخواسته ای در رشته وجود نداشته باشد.
به جدول زیر توجه بفرمایید (خروجی query فوق)
نتیجه مطلوب ما آن دو سطری است که در کادر بنفش هستند. که اگر به ستون Ix اشان توجه کنید مقدارش برابر با 0 است.
لطفا به سطر اول جدول توجه بفرمایید مشاهده میشود که هر 4 کاراکتر @ یکباره از رشته حذف شدند که بدلیل استفاده از تابع REPLACE میباشد.
احتمالا در بیشتر مقالات (فارسی/انگلیسی) عبارات هایی مثل نمونههای زیر را دیده اید :
در این مقاله قصد داریم بپردازیم به «مقید سازی پارامترهای نوع جنریک» و اینکه چه کاربردی دارند و در چه زمانی بهتر است از آنها استفاده کنیم و نحوه استفاده از آنها چگونه است. فرض میکنیم که خوانندهی محترم با مفاهیم جنریک آشنایی دارد. در صورتیکه با جنریکها آشنا نیستید ابتدا مروری داشته باشید بر جنریکها و بعد این مقاله را مطالعه فرمایید؛ به این دلیل که موضوع مورد بحث بر پایهی جنریکها میباشد.
همانطور که مطلع هستید هر عنصری جنریکی را که تعریف میکنید حداقل دارای یک پارامتر نوع هست و در زمان بکارگیری آن جنریک باید نوع آن را مشخص نمایید. برای نمونه مثال زیر را در نظر بگیرید :
کلاس فوق یک کلاس جنریک است که در هنگام ساخت نمونهای از آن، باید ابتدا data type نوعی را که که میخواهیم با آن کار کنیم، تعیین کنیم. برای مثال در کد فوق در هنگام ساخت نمونهای از آن، نوع int را برای آن مشخص میکنیم و هر وقت بخواهیم متد Add آن را فراخوانی کنیم، فقط نوعی را قبول خواهد کرد که در ابتدا برای آن تعیین کرده ایم (int):
سؤال: میخواهیم فقط نوعهایی را بتوان به T نسبت داد که از نوع ارجاعی (reference type) هستن و یا فقط نوع هایی را به T نسبت داد که یک سازنده دارند؛ چگونه؟
ایجاد قیدها یا محدودیتها بر روی پارامترهای جنریکها شامل پنج حالت میباشد:
حالت اول : Where T:struct
در این حالت T باید یک ساختار باشد .
حالت دوم : where T:class
T باید یک نوع ارجاعی باشد. اگر در مثال فوق این قید را به آن اضافه کنیم، در هنگام ساخت نمونهای از کلاس فوق، اگر یک نوع value type را به T نسبت دهیم، در هنگام وارد کردن یک نوع value type با خطا مواجه خواهیم شد. مثال:
و برای استفاده :
حالت سوم : ()Where T:new
نوعی که به T نسبت داده میشود باید یک سازندهی پیش فرض داشته باشد.
داخل پرانتز : سازندهی پیش فرض: زمانی که شما یک کلاس مینویسید اگر آن کلاس دارای هیچ سازندهای نباشد، کامپایلر یک سازندهی بدون پارامتر را به کلاس فوق اضافه میکند که کار آن مقدار دهی به فیلدهای کلاس است. در اینجا از مقادیر پیش فرض استفاده میشود. مثلا برای int مقدار صفر و برای string مقدار "" و به همین ترتیب.
اگر از مقدار دهی پیش فرض توسط کامپایلر خرسند نیستید، میتوانید سازنده پیش فرض را تغییر داده و مطابق میل خود فیلدها را مقدار دهی اولیه کنید .
حالت چهارم : where T:NameOfBaseClass
نوعی که به T نسبت داده میشود باید از کلاس NameOfBaseClass ارث بری کرده باشد.
حالت پنجم : where T:NameOfInterface
همانند حالت چهارم میباشد؛ با این تفاوت: نوعی که به T نسبت داده میشود باید واسط NameOfInterface را پیاده سازی کرده باشد.
پنج حالت فوق نمونههایی از ایجاد محدودیت بر روی پرامتر نوع اعضای جنریک بودند و اما در ادامه قصد داریم نکاتی را در این باب، بیان کنیم:
نکته اول : میتوانید محدودیتهای فوق را با هم ترکیب کنید برای اینکار آنها را با کاما از هم جدا کنید :
نوعی که به T نسبت داده میشود
نکته چهارم : زمانیکه کلاس و یا متدهای شما بیش از یک نوع پارامتر از نوع جنریک را دریافت میکنند، باید محدودیتهای مورد نظر را برای هر کدام به صورت جداگانه قید کنید. به طور مثال به کلاس زیر که دو پارمتر T و K را دارد، باید برای هر کدام جداگانه محدودیتهای مورد نظر را اعمال کنیم (در صورت نیاز):
where T:clas where T:struc ...
همانطور که مطلع هستید هر عنصری جنریکی را که تعریف میکنید حداقل دارای یک پارامتر نوع هست و در زمان بکارگیری آن جنریک باید نوع آن را مشخص نمایید. برای نمونه مثال زیر را در نظر بگیرید :
public class MyCollection<T> { private List<T> collections = new List<T>(); public void Add(T value) { collections.Add(value); } }
MyCollection<int> myintObj = new MyCollection<int>(); myintObj.Add(12); myintObj.Add(33); myintObj.Add(33.3);// ERROR z
ایجاد قیدها یا محدودیتها بر روی پارامترهای جنریکها شامل پنج حالت میباشد:
حالت اول : Where T:struct
در این حالت T باید یک ساختار باشد .
حالت دوم : where T:class
T باید یک نوع ارجاعی باشد. اگر در مثال فوق این قید را به آن اضافه کنیم، در هنگام ساخت نمونهای از کلاس فوق، اگر یک نوع value type را به T نسبت دهیم، در هنگام وارد کردن یک نوع value type با خطا مواجه خواهیم شد. مثال:
public class MyCollection<T> where T:class { private List<T> collections = new List<T>(); public void Add(T value) { collections.Add(value); } }
MyCollection<int> myintObj = new MyCollection<int>(); // ERROR , int is value type
حالت سوم : ()Where T:new
نوعی که به T نسبت داده میشود باید یک سازندهی پیش فرض داشته باشد.
داخل پرانتز : سازندهی پیش فرض: زمانی که شما یک کلاس مینویسید اگر آن کلاس دارای هیچ سازندهای نباشد، کامپایلر یک سازندهی بدون پارامتر را به کلاس فوق اضافه میکند که کار آن مقدار دهی به فیلدهای کلاس است. در اینجا از مقادیر پیش فرض استفاده میشود. مثلا برای int مقدار صفر و برای string مقدار "" و به همین ترتیب.
اگر از مقدار دهی پیش فرض توسط کامپایلر خرسند نیستید، میتوانید سازنده پیش فرض را تغییر داده و مطابق میل خود فیلدها را مقدار دهی اولیه کنید .
حالت چهارم : where T:NameOfBaseClass
نوعی که به T نسبت داده میشود باید از کلاس NameOfBaseClass ارث بری کرده باشد.
حالت پنجم : where T:NameOfInterface
همانند حالت چهارم میباشد؛ با این تفاوت: نوعی که به T نسبت داده میشود باید واسط NameOfInterface را پیاده سازی کرده باشد.
پنج حالت فوق نمونههایی از ایجاد محدودیت بر روی پرامتر نوع اعضای جنریک بودند و اما در ادامه قصد داریم نکاتی را در این باب، بیان کنیم:
نکته اول : میتوانید محدودیتهای فوق را با هم ترکیب کنید برای اینکار آنها را با کاما از هم جدا کنید :
public class MyCollection<T> where T:class,IDisposable,new() { //content }
- باید از نوع ارجاعی باشد.
- باید واسط IDisposable را پیاده سازی کرده باشد.
- باید یک سازندهی پیش فرض داشته باشد.
نکته دوم : زمانیکه از چندین محدودیت استفاده میکنید مثل مثال فوق، باید محدودیت ()new در آخرین جایگاه محدودیتها قرار گیرد؛ در غیر اینصورت با خطای زمان ترجمه روبه رو خواهید شد .
نکته سوم : میتوان محدودیتهای فوق را علاوه بر کلاس، بر روی متدهای جنریک نیز اعمال کنید:
public void Swap<T>(ref T val1,ref T val2) where T:struct { //content }
public class MyCollection<T,K> where T:class where K:IDisposable,new() { //content }
معادل این مطلب برای ASP.NET Core 6x
- روش Model binder دیگر با نگارشهای جدیدتر ASP.NET Core کار نمیکند و همچنین محدودیتهای زیادی هم مانند عدم پشتیبانی از پارامترهای [FromBody] را دارد؛ چون بکارگیری [FromBody]، استفادهی از تمام Model binders سفارشی را لغو میکند.
نظرات مطالب
معرفی کتابخانه Loader برای بارگذاری JS و CSS
ممنون از شما. این روش احتمالا با روشهای یکی کردن اسکریپتها یا فایلهای CSS با هم قابل استفاده نیست (کاهش رفت و برگشت به سرور با یکی کردن چند فایل CSS یا اسکریپت با هم مثل روشهای bundling & minification در ASP.NET MVC).
پیشتر مطلب «Count یا Any » را در این سایت مطالعه کردهاید که در پایان آن این نتیجه گیری صورت گرفتهاست:
«از این پس حین استفاده از انواع و اقسام لیستها، آرایهها، IEnumerableها و امثال آنها، جهت بررسی خالی بودن یا نبودن آنها تنها از متد Any فراهم شده توسط LINQ استفاده نمائید.»
اکنون پس از سالها، قصد داریم صحت این مساله را با NET 5.0. بررسی کنیم که آیا هنوز هم متد Any، بهترین متد بررسی خالی بودن مجموعهها و آرایههای NET 5.0. است یا خیر؟
نحوهی بررسی کارآیی روشهای مختلف خالی بودن مجموعهها و آرایهها در C# 9.0
در ابتدا یک لیست، یک Enumerable و یک آرایه را به صورت زیر مقدار دهی میکنیم و هر سهی اینها میتوانند نال هم باشند:
اکنون که C# 9.0 در اختیار ما است به همراه pattern matching و همچنین Null Conditional Operator و غیره، میتوان روشهای زیر را برای بررسی خالی بودن این مجموعهها و آرایهها بکار گرفت:
1- استفاده از Null coalescing برای بررسی نال بودن مجموعه و سپس استفاده از متد Any برای بررسی خالی بودن آن:
2- استفاده از pattern matching برای بررسی نال بودن مجموعه و سپس استفاده از متد Any برای بررسی خالی بودن آن:
3- استفاده از روش سنتی مقایسهی مستقیم با null و سپس استفاده از متد Any برای بررسی خالی بودن آن:
4- استفاده از Null Conditional Operator برای بررسی نال بودن و سپس استفاده از متد Any برای بررسی خالی بودن آن:
5- استفاده از pattern matching برای بررسی مقدار خاصیت Count یک لیست یا آرایه. البته Enumerableها به همراه این خاصیت نیستند و یا باید آنها را به لیست و یا آرایه تبدیل کرد و یا میتوان متد ()Count آنها را فراخوانی نمود:
6- استفاده از Null Conditional Operator برای بررسی نال بودن و سپس استفاده از مقدار خاصیت Count لیست، برای بررسی خالی بودن آن:
7- استفاده از روش سنتی مقایسهی مستقیم با null و سپس استفاده از مقدار خاصیت Count لیست، برای بررسی خالی بودن آن:
کدهای کامل این بررسی به صورت زیر هستند: AnyCountBenchmark.zip
ابتدا ارجاعی به BenchmarkDotNet به برنامه اضافه شدهاست:
و سپس کدهای زیر، بررسی کارآیی روشهای مختلف تعیین خالی بودن مجموعهها را انجام میدهند:
به همراه سناریوهای مختلف زیر:
یکبار اجرای آن، نتیجهی زیر را به همراه داشت:
نتایج حاصل:
- بررسی خالی بودن آرایهها، بسیار سریعتر از بررسی خالی بودن لیستها و این مورد نیز سریعتر از Enumerableها است.
- اگر از آرایهها و یا لیستها استفاده میکنید، بررسی خاصیت Length و یا خاصیت Count آنها، بسیار سریعتر از بکارگیری متد Any بر روی آنها است.
- اگر از Enumerableها استفاده میکنید، استفاده از متد Any بر روی آنها، بسیار سریعتر از بکارگیری متد ()Count و یا تبدیل آنها به لیست و سپس بررسی خاصیت Count آنها است.
- بررسی نال بودن با pattern matching یا همان is null، نسبت به روشی سنتی استفادهی از null ==، سریعتر است. علت آنرا در مطلب «روش ترجیح داده شدهی مقایسه مقادیر اشیاء با null از زمان C# 7.0 به بعد» میتوانید مطالعه کنید.
بنابراین برای بررسی خالی بودن آرایهها و لیستها، بهتر است از خاصیت Length و یا Count آنها استفاده کرد و برای Enumerableها از متد ()Any.
«از این پس حین استفاده از انواع و اقسام لیستها، آرایهها، 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.
بازخوردهای دوره
شروع به کار با RavenDB
لطفا پیشنیازهای بحث را که در ابتدای مطلب عنوان شده مطالعه کنید تا با مفاهیم اولیه و علت وجودی بانکهای اطلاعاتی NoSQL آشنا شوید.