این موارد را با استفاده از ایدهی جالب «افزونهی Heap Allocations Viewer برای ریشارپر » بهتر میتوان مشاهده کرد.
این موارد را با استفاده از ایدهی جالب «افزونهی Heap Allocations Viewer برای ریشارپر » بهتر میتوان مشاهده کرد.
using System.Web.Mvc;
namespace MvcApplication16.Controllers
{
public class HomeController : Controller
{
[OutputCache(Duration = 60, VaryByParam = "none")]
public ActionResult Index()
{
return View();
}
}
}
using System;
using System.Web.Mvc;
namespace MvcApplication16.Controllers
{
public class HomeController : Controller
{
[OutputCache(Duration = 60, VaryByParam = "none")]
public ActionResult Index()
{
ViewBag.ControllerTime = DateTime.Now;
return View();
}
}
}
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>@ViewBag.ControllerTime</p>
<p>@DateTime.Now</p>
using System;
using System.Web.Mvc;
namespace MvcApplication16.Controllers
{
public class HomeController : Controller
{
[OutputCache(Duration = 60, VaryByParam = "none")]
public ActionResult Index(string parameter)
{
ViewBag.Msg = parameter ?? string.Empty;
ViewBag.ControllerTime = DateTime.Now;
return View();
}
}
}
@{
ViewBag.Title = "Index";
}
<h2>@ViewBag.Msg</h2>
<p>@ViewBag.ControllerTime</p>
<p>@DateTime.Now</p>
@using (Html.BeginForm())
{
@Html.TextBox("parameter")
<input type="submit" />
}
[OutputCache(Duration = 60, VaryByParam = "parameter")]
public ActionResult Index(string parameter)
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
using System;
using System.Web.Mvc;
namespace MvcApplication16.Helper
{
/// <summary>
/// Adds "Cache-Control: private, max-age=0" header,
/// ensuring that the responses are not cached by the user's browser.
/// </summary>
public class NoCachingAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.HttpContext.Response.CacheControl = "private";
filterContext.HttpContext.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(0));
}
}
}
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Aggressive" location="ServerAndClient" duration="300"/>
<add name="Mild" duration="100" location="Server" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
[OutputCache(CacheProfile = "Aggressive", VaryByParam = "parameter")]
public ActionResult Index(string parameter)
@{ Response.WriteSubstitution(ctx => DateTime.Now.ToShortTimeString()); }
using System;
using System.Web;
using System.Web.Caching;
namespace MvcApplication16.Helper
{
public static class CacheManager
{
public static void CacheInsert(this HttpContextBase httpContext, string key, object data, int durationMinutes)
{
if (data == null) return;
httpContext.Cache.Add(
key,
data,
null,
DateTime.Now.AddMinutes(durationMinutes),
TimeSpan.Zero,
CacheItemPriority.AboveNormal,
null);
}
public static T CacheRead<T>(this HttpContextBase httpContext, string key)
{
var data = httpContext.Cache[key];
if (data != null)
return (T)data;
return default(T);
}
public static void InvalidateCache(this HttpContextBase httpContext, string key)
{
httpContext.Cache.Remove(key);
}
}
}
[Authorize]
[OutputCache(Duration = 60)]
public ActionResult Index()
در این بخش در حال توسعه ویژگی نرم افزاری هستیم که در آن هرکاربر به عنوان یک کاربر اصلی برای یک محصول تخصیص داده میشود. در طراحی اصلی ما فقط اجازه میدهیم یک کاربر متعلق به هر محصول باشد، اما امکان چنین تقاضایی وجود دارد که چند کاربر نیز به یک محصول اختصاص داده شوند.
در این صورت، اگر پایگاه داده را به نحوی تغییر دهیم که شناسهی حساب کاربران را در لیستی که با کاما از یکدیگر جدا شدهاند ذخیره نماییم، خیلی سادهتر به نظر میرسد نسبت به اینکه بصورت جداگانه آنها را ثبت نماییم.
برنامه نویسان معمولا برای جلوگیری از ایجاد جدول واسطی [1] که رابطههای چند به چند زیادی دارد از یک لیست که با کاما دادههایش از هم جدا شدهاند، استفاده میکنند. بدین جهت اسم این بخش jaywalking ,antipatten میباشد، زیرا jaywalking نیز عملیاتی است که از تقاطع جلوگیری میکند.
1.1 هدف: ذخیره کردن چندین صفت
طراحی کردن جدولی که ستون آن فقط یک مقدار دارد، بسیار ساده و آسان میباشد. شما میتوانید نوع دادهایی که متعلق به ستون میباشد را انتخاب نمایید. مثلا از نوع (int,date…)
چگونه میتوانیم مجموعهایی از مقادیری که به یکدیگر مرتبط هستند را در یک ستون ذخیره نماییم ؟
در مثال ردیابی خطای پایگاه داده، ما یک محصول را به یک کاربر، با استفاده از ستونی که نوع آن integer است، مرتبط مینماییم. هر کاربر ممکن است محصولاتی داشته باشد و هر محصول به یک contact اشاره کند. بنابراین یک ارتباط چند به یک بین محصولات و کاربر برقرار است. برعکس این موضوع نیز صادق است؛ یعنی امکان دارد هر محصول متعلق به چندین کاربر باشد و یک ارتباط یک به چند ایجاد شود. در زیر جدول محصولات را به صورت عادی آورده شده است:
CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(1000), account_id BIGINT UNSIGNED, -- . . . FOREIGN KEY (account_id) REFERENCES Accounts(account_id) ); INSERT INTO Products (product_id, product_name, account_id) VALUES (DEFAULT, 'Visual TurboBuilder' , 12);
CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(1000), account_id VARCHAR(100), -- comma-separated list -- . . . ); INSERT INTO Products (product_id, product_name, account_id) VALUES (DEFAULT, 'Visual TurboBuilder' , '12,34' );
اکنون مشکلات کارایی و جامعیت دادهها را در این راه حل پیشنهادی بررسی مینماییم .
بدست آوردن محصولاتی برای یک کاربر خاص
بدلیل اینکه تمامی شناسهی کاربران که بصورت کلید خارجی جدول Products میباشند به صورت رشته در یک فیلد ذخیره شدهاند و حالت ایندکس بودن آنها از دست رفته است، بدست آوردن محصولاتی برای یک کاربر خاص سخت میباشد. به عنوان مثال بدست آوردن محصولاتی که کاربری با شناسهی 12 خریداری نموده بهصورت زیر میباشد:
SELECT * FROM Products WHERE account_id REGEXP '[[:<:]]12[[:>:]]' ;
SELECT * FROM Products AS p JOIN Accounts AS a ON p.account_id REGEXP '[[:<:]]' || a.account_id || '[[:>:]]' WHERE p.product_id = 123;
SELECT product_id, LENGTH(account_id) - LENGTH(REPLACE(account_id, ',' , '' )) + 1 AS contacts_per_product FROM Products;
UPDATE Products SET account_id = account_id || ',' || 56 WHERE product_id = 123;
<?php $stmt = $pdo->query( "SELECT account_id FROM Products WHERE product_id = 123"); $row = $stmt->fetch(); $contact_list = $row['account_id' ]; // change list in PHP code $value_to_remove = "34"; $contact_list = split(",", $contact_list); $key_to_remove = array_search($value_to_remove, $contact_list); unset($contact_list[$key_to_remove]); $contact_list = join(",", $contact_list); $stmt = $pdo->prepare( "UPDATE Products SET account_id = ? WHERE product_id = 123"); $stmt->execute(array($contact_list));
INSERT INTO Products (product_id, product_name, account_id) VALUES (DEFAULT, 'Visual TurboBuilder' , '12,34,banana' );
UPDATE Products SET account_id = '10,14,18,22,26,30,34,38,42,46' WHERE product_id = 123;
UPDATE Products SET account_id = '101418,222630,343842,467790' WHERE product_id = 123;
CREATE TABLE Contacts ( product_id BIGINT UNSIGNED NOT NULL, account_id BIGINT UNSIGNED NOT NULL, PRIMARY KEY (product_id, account_id), FOREIGN KEY (product_id) REFERENCES Products(product_id), FOREIGN KEY (account_id) REFERENCES Accounts(account_id) );
جدول
Contacts یک جدول رابطه ایی بین جداول Products,Accounts
بدست آوردن محصولات برای کاربران و موارد مربوط به آن
ما براحتی میتوانیم تمامی محصولاتی که مختص به یک کاربر هستند را بدست آوریم. در این شیوه خاصیت ایندکس بودن شناسهی کاربران حفظ میشود به همین دلیل queryهای آن برای خواندن و بهینه کردن راحتتر میباشند. در این روش به کاراکتری برای جدا کردن ورودیها از یکدیگر نیاز نداریم چون هر کدام از آنها در یک سطر جداگانه ثبت میشوند. برای ویرایش کردن کاربرانی که یک محصول را خریداری نموده اند، کافیست یک سطر از جدول واسط را اضافه یا حذف نماییم. درنمونه کد زیر، ابتدا در جدول Contacts کاربری با شناسهی 34 که محصولی با شناسهی 456 را خریداری کرده، درج شده است و در خط بعد عملیات حذف با شرط آنکه شناسهی کاربر و محصول به ترتیب 34،456 باشد روی جدول Contacts اعمال شده است.
INSERT INTO Contacts (product_id, account_id) VALUES (456, 34); DELETE FROM Contacts WHERE product_id = 456 AND account_id = 34;
ایجاد توابع تجمیعی
به عنوان نمونه در مثال زیر براحتی ما میتوانیم تعداد محصولات در هر حساب کاربری را بدست آوریم:
SELECT account_id, COUNT(*) AS products_per_account FROM Contacts GROUP BY account_id;
اعتبارسنجی شناسه محصولات
از آنجاییکه مقادیری که در جدول قرار دارند کلید خارجی میباشند میتوان صحت اعتبار آنها را بررسی نمود. بعنوان مثال Contacts.account_id به Account.account_id اشاره میکند. در ضمن برای هر فیلد نوع آن را میتوان مشخص کرد تا فقط همان نوع داده را بپذیرد.
محدودیت طول لیست
نسبت به روش قبلی تقریبا در این حالت محدودیتی برای تعداد کاراکترهای ورودی نداریم.
مزیتهای دیگر استفاده از جدول واسط
کارایی روش دوم بهتر از حالت قبلی میباشد چون ایندکس بودن شناسهها حفظ شده است. همچنین براحتی میتوانیم فیلدی را به این جدول اضافه نماییم مثلا (time, date… )
public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector)
Recipe[] recipes = { new Recipe {Id = 1, Name = "Mashed Potato"}, new Recipe {Id = 2, Name = "Crispy Duck"}, new Recipe {Id = 3, Name = "Sachertorte"} }; // inner sequence Review[] reviews = { new Review {RecipeId = 1, ReviewText = "Tasty!"}, new Review {RecipeId = 1, ReviewText = "Not nice :("}, new Review {RecipeId = 1, ReviewText = "Pretty good"}, new Review {RecipeId = 2, ReviewText = "Too hard"}, new Review {RecipeId = 2, ReviewText = "Loved it"} }; var query = recipes // recipes توالی خارجی .Join(reviews, // reviewsتوالی داخلی (Recipe outerKey) => outerKey.Id, // کلید انخاب شده از توالی خارجی (Review innerKey) => innerKey.RecipeId, // کلید انتخاب شده از توالی داخلی // نحوه قالب بندی خروجی (recipe, review) => recipe.Name + " - " + review.ReviewText); foreach (string item in query) { Console.WriteLine(item); }
Mashed Potato - Tasty! Mashed Potato - Not nice :( Mashed Potato - Pretty good Crispy Duck - Too hard Crispy Duck - Loved it
var query = recipes.Join (reviews, outerKey => outerKey.Id, innerKey => innerKey.RecipeId, (recipe, review) => recipe.Name + " - " + review.ReviewText);
var query = from recipe in recipes join review in reviews on recipe.Id equals review.RecipeId select new //انواع بی نام { RecipeName = recipe.Name, RecipeReview = review.ReviewText }; foreach (var item in query) { Console.WriteLine(item.RecipeName + " - " + item.RecipeReview); }
// outer sequence Recipe[] recipes = { new Recipe {Id = 1, Name = "Mashed Potato"}, new Recipe {Id = 2, Name = "Crispy Duck"}, new Recipe {Id = 3, Name = "Sachertorte"} }; // inner sequence Review[] reviews = { new Review {RecipeId = 1, ReviewText = "Tasty!"}, new Review {RecipeId = 1, ReviewText = "Not nice :("}, new Review {RecipeId = 1, ReviewText = "Pretty good"}, new Review {RecipeId = 2, ReviewText = "Too hard"}, new Review {RecipeId = 2, ReviewText = "Loved it"} }; var query = recipes .GroupJoin( reviews, (Recipe outerKey) => outerKey.Id,//outer key (Review innerKey) => innerKey.RecipeId,//inner key (Recipe recipe, IEnumerable<Review> rev )=>تعریف ساختار گروهها new { RecipeName = recipe.Name, Reviews = rev } ); foreach (var item in query) { Console.WriteLine($"Reviews for {item.RecipeName}"); foreach (var review in item.Reviews) { Console.WriteLine($" - {review.ReviewText}"); } }
Reviews for Mashed Potato - Tasty! - Not nice :( - Pretty good Reviews for Crispy Duck - Too hard - Loved it Reviews for Sachertorte
var query = from recipe in recipes join review in reviews on recipe.Id equals review.RecipeId into reviewGroup select new //انواع بی نام { RecipeName = recipe.Name, Reviews = reviewGroup//کلیه بازخوردها مرتبط با یک دستور غذایی };
Reviews for Mashed Potato - Tasty! - Not nice :( - Pretty good Reviews for Crispy Duck - Too hard - Loved it Reviews for Sachertorte
public class Ingredient { public string Name { get; set; } public int Calories { get; set; } } string[] names = { "Flour", "Butter", "Sugar" }; int[] calories = { 100, 400, 500 }; IEnumerable<Ingredient> ingredients = names.Zip(calories, (name, calorie) => new Ingredient { Name = name, Calories = calorie }); foreach (var item in ingredients) { Console.WriteLine($"{item.Name} has {item.Calories} calories"); }
Flour has 100 calories Butter has 400 calories Sugar has 500 calories
using (PersonDbEntities context = new PersonDbEntities()) { var people = from p in context.Persons select p; foreach (Person person in people) { Console.WriteLine("{0}, {1}", person.LastName, person.FirstName); } Console.ReadLine(); }
using (PersonDbEntities context = new PersonDbEntities()) { var students = from p in context.Persons.OfType<BusinessStudent>() select p; foreach (BusinessStudent student in students) { Console.WriteLine("{0}, {1}: Degree {2}, Discipline {3}", student.LastName, student.FirstName, student.Degree, student.Discipline); } Console.ReadLine(); }
using (PersonDbEntities context = new PersonDbEntities()) { var people = from p in context.Persons select p; foreach (Person person in people) { Console.WriteLine("{0}, {1}", person.LastName, person.FirstName); if (person is Student) Console.WriteLine(" Degree: {0}", ((Student)person).Degree); if (person is BusinessStudent) Console.WriteLine(" Discipline: {0}", ((BusinessStudent)person).Discipline); } Console.ReadLine(); }
{ _id: POST_ID title: TITLE_OF_POST, description: POST_DESCRIPTION, by: POST_BY, url: URL_OF_POST, tags: [TAG1, TAG2, TAG3], likes: TOTAL_LIKES, comments: [ { user:'COMMENT_BY', message: TEXT, dateCreated: DATE_TIME, like: LIKES }, { user:'COMMENT_BY', message: TEXT, dateCreated: DATE_TIME, like: LIKES } ] }
namespace EFCorePgExercises.Entities { public class Member { // ... public virtual ICollection<Member> Children { get; set; } public virtual Member Recommender { set; get; } public int? RecommendedBy { set; get; } // ... } }
var id = 27; var entity27WithAllOfItsParents = context.Members .Where(member => member.MemId == id || member.Children.Any(m => member.MemId == m.RecommendedBy)) .ToList() //It's a MUST - get all children from the database .FirstOrDefault(x => x.MemId == id);// then get the root of the tree
namespace EFCorePgExercises.Exercises.RecursiveQueries { public static class RecursiveUtils { public static void FindParents(Member member, List<dynamic> actualResult) { if (member == null || member.Recommender == null) { return; } var item = member.Recommender; actualResult.Add(new { Recommender = item.MemId, item.FirstName, item.Surname }); if (item.Recommender != null) { FindParents(item, actualResult); } } } }
var actualResult = new List<dynamic>(); RecursiveUtils.FindParents(entity27WithAllOfItsParents, actualResult);
var id = 1; var entity1WithAllOfItsDescendants = context.Members .Include(member => member.Children) .Where(member => member.MemId == id || member.Children.Any(m => member.MemId == m.RecommendedBy)) .ToList() //It's a MUST - get all children from the database .FirstOrDefault(x => x.MemId == id);// then get the root of the tree
SELECT [m].[MemId], [m].[Address], [m].[FirstName], [m].[JoinDate], [m].[RecommendedBy], [m].[Surname], [m].[Telephone], [m].[ZipCode], [m0].[MemId], [m0].[Address], [m0].[FirstName], [m0].[JoinDate], [m0].[RecommendedBy], [m0].[Surname], [m0].[Telephone], [m0].[ZipCode] FROM [Members] AS [m] LEFT OUTER JOIN [Members] AS [m0] ON [m].[MemId] = [m0].[RecommendedBy] WHERE ([m].[MemId] = 1) OR EXISTS (SELECT 1 FROM [Members] AS [m1] WHERE ([m].[MemId] = [m1].[RecommendedBy]) AND ([m].[MemId] = [m1].[RecommendedBy])) ORDER BY [m].[MemId], [m0].[MemId];
namespace EFCorePgExercises.Exercises.RecursiveQueries { public static class RecursiveUtils { public static void FindChildren(Member member, List<dynamic> actualResult) { if (member == null) { return; } foreach (var item in member.Children) { actualResult.Add(new { item.MemId, item.FirstName, item.Surname }); if (item.Children != null) { FindChildren(item, actualResult); } } } } }
var actualResult = new List<dynamic>(); RecursiveUtils.FindChildren(entity1WithAllOfItsDescendants, actualResult);
<!DOCTYPE html> <html> <head> <title>event propagation demo</title> </head> <body> <section> <h1>nested divs</h1> <div>one <div>child of one <div>child of child of one</div> </div> </div> </section> </body> </html>
1.window 2.document 3.<html> 4.<body> 5.<section> 6.<div>one 7.<div>child of one 8.<div>child of child of one
9.<div>child of child of one 10.<div>child of one 11.<div>one 12.<section> 13.<body> 14.<html> 15.document 16.window
<div> <button type="button">do something</button> </div> <form method="POST" action="/user"> <label>Enter user name: <input name="user"> </label> <button type="submit">submit</button> </form>
// submits the form $('FORM').trigger('submit'); // submits the form by clicking the button $('BUTTON[type="submit"]').trigger('click'); // focuses the text input $('INPUT').trigger('focus'); // removes focus from the text input $('INPUT').trigger('blur');
// submits the form $('FORM').submit(); // submits the form by clicking the button $('BUTTON[type="submit"]').click(); // focuses the text input $('INPUT').focus(); // removes focus from the text input $('INPUT').blur();
// clicks the first button - the click event does not bubble $('BUTTON[type="button"]').triggerHandler('click');
// submits the form document.querySelector('FORM').submit(); // submits the form by clicking the button document.querySelector('BUTTON[type="submit"]').click(); // focuses the text input document.querySelector('INPUT').focus(); // removes focus from the text input document.querySelector('INPUT').blur();
var clickEvent; if (typeof Event === 'function') { clickEvent = new Event('click', {bubbles: false}); } else { clickEvent = document.createEvent('Event'); clickEvent.initEvent('click', false, true); } document.querySelector('BUTTON[type="button"]').dispatchEvent(clickEvent);
// Triggers a custom "image-removed" element, // which bubbles up to ancestor elements. $libraryElement.trigger('image-removed', {id: 1});
var event = new CustomEvent('image-removed', { bubbles: true, detail: {id: 1} }); libraryElement.dispatchEvent(event);
var event = document.createEvent('CustomEvent'); event.initCustomEvent('image-removed', false, true, {id: 1}); libraryElement.dispatchEvent(event);
var event; // If the `CustomEvent` constructor function is not supported, // fall back to `createEvent` method. if (typeof CustomEvent === 'function') { event = new CustomEvent('image-removed', { bubbles: true, detail: {id: 1} }); } else { event = document.createEvent('CustomEvent'); event.initCustomEvent('image-removed', false, true, { id: 1 }); } libraryElement.dispatchEvent(event);
$(window).on('resize', function() { // react to new window size });
// remove all resize listeners - usually a bad idea $(window).off('resize');
var resizeHandler = function() { // react to new window size }; $(window).on('resize', resizeHandler); // ...later // remove only our resize handler $(window).off('resize', resizeHandler);
$(someElement).one('click', function() { // handle click event });
<button onclick="handleButtonClick()">click me</button>
buttonEl.onclick = function() { // handle button click };
buttonEl.addEventListener('click', function() { // handle button click });
window.addEventListener('resize', function() { // react to new window size });
var resizeHandler = function() { // react to new window size }; window.addEventListener('resize', resizeHandler); // ...later // remove only our resize handler window.removeEventListener('resize', resizeHandler);
someElement.addEventListener('click', function(event) { // handle click event }, { once: true });
var clickHandler = function() { // handle click event // ...then unregister handler someElement.removeEventListener('click', clickHandler); }; someElement.addEventListener('click', clickHandler);
$(window).on('mousedown', function(event) { event.preventDefault(); });
window.addEventListener('mousedown', function(event) { event.preventDefault(); });
$someElement.on('click', function(event) { event.stopPropagation(); });
// stop propagation during capturing phase someElement.addEventListener('click', function(event) { event.stopPropagation(); }, true);
// stop propagation during bubbling phase someElement.addEventListener('click', function(event) { event.stopPropagation(); });
$someElement.on('click', function(event) { event.stopImmediatePropagation(); });
someElement.addEventListener('click', function(event) { event.stopImmediatePropagation(); });
$uploaderElement.trigger('uploadError', { filename: 'picture.jpeg' });
$uploaderParent.on('uploadError', function(event, data) { showAlert('Failed to upload ' + data.filename); });
// send the failed filename w/ an error event var event = new CustomEvent('uploadError', { bubbles: true, detail: {filename: 'picture.jpeg'} }); uploaderElement.dispatchEvent(event); // ...and this is a listener for the event uploaderParent.addEventListener('uploadError', function(event) { showAlert('Failed to upload ' + event.detail.filename); });
// send the failed filename w/ an error event var event = document.createEvent('CustomEvent'); event.initCustomEvent('uploadError', true, true, { filename: 'picture.jpeg' }); uploaderElement.dispatchEvent(event); // ...and this is a listener for the event uploaderParent.addEventListener('uploadError', function(event) { showAlert('Failed to upload ' + event.detail.filename); });
$(window).on('load', function() { // page is fully rendered });
window.addEventListener('load', function() { // page is fully rendered });
$(document).ready(function() { // markup is on the page }); //or $(function() { // markup is on the page });
document.addEventListener('DOMContentLoaded', function() { // markup is on the page });
$('IMG').on('load', function() { // image has successfully loaded }); $('IMG').on('error', function() { // image has failed to load });
document.querySelector('IMG').addEventListener('load', function() { // image has successfully loaded }); document.querySelector('IMG').addEventListener('error', function() { // image has failed to load });
$(window).on('beforeunload', function() { return 'Are you sure you want to unload the page?'; });
window.addEventListener('beforeunload', function(event) { var message = 'Are you sure you want to unload the page?'; event.returnValue = message; return message; });
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(); }
var list = _idsList ?? new List<int>(); if (list.Any() is false) { }
if (_idsList is null || _idsList.Any() is false) { }
if (_idsList == null || _idsList.Any() is false) { }
if (_idsList?.Any() is false) { }
if (_idsList is { Count: > 0 } is false) { }
if (_idsList?.Count == 0) { }
if (_idsList == null || _idsList.Count == 0) { }
<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 } }