مطالب دوره‌ها
ارائه کاربری ساده‌تر انتخاب چندین آیتم از یک لیست به کمک افزونه TagIt در ASP.NET MVC
چندی قبل مطلبی را در مورد بررسی تفصیلی رابطه چند به چند در این سایت مطالعه کردید. در آن مطلب صرفا به بحث ذخیره سازی اطلاعات دریافتی از کاربر اشاره شد. برای مثال اگر مطلبی چندین برچسب دارد، چگونه باید این‌ها را در بانک اطلاعاتی به نحو صحیحی ذخیره کرد.
در مطلب جاری قصد داریم با نحوه ارائه یک UI کاربر پسند برای این منظور آشنا شویم و سؤال مهم هم این است: «چگونه می‌توان کار کاربر را در حین وارد کردن تعدادی از برچسب‌های مرتبط با یک مطلب ساده‌تر کرد؟». برای این منظور یکی از راه حل‌هایی که در بسیاری از سایت‌ها مرسوم شده است، استفاده از افزونه‌هایی مانند jQuery TagIt می‌باشد که در ادامه با نحوه استفاده از آن در ASP.NET MVC آشنا خواهیم شد.


پیشنیازها:
دریافت افزونه TagIt
همچنین دریافت jQuery UI (افزونه TagIt برای نمایش لیست Auto Complete آیتم‌ها از jQuery UI در پشت صحنه استفاده می‌کند)
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/TagIt/jquery-ui-1.8.23.custom.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/TagIt/tagit-simple-blue.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.9.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Content/TagIt/jquery-ui-1.8.23.custom.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Content/TagIt/tagit.js")" type="text/javascript"></script>
    @RenderSection("JavaScript", required: false)
</head>
که نهایتا نیاز است یک چنین تعاریفی را به فایل layout برنامه اضافه کنیم.

آشنایی با مدل برنامه

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace jQueryMvcSample04.Models
{
    public class BlogPostViewModel
    {
        [DisplayName("عنوان"), Required(ErrorMessage = "*")]
        public string Title { set; get; }

        [DisplayName("متن"), Required(ErrorMessage = "*")]
        public string Body { set; get; }

        /// <summary>
        /// آرایه‌ای محدود از برچسب‌های این مطلب خاص به صورت جی‌سون که پیشتر ثبت شده است
        /// هدف استفاده در حین ویرایش مطلب
        /// </summary>
        public string InitialTags { set; get; }

        /// <summary>
        /// آرایه‌ای جی‌سونی از تمام برچسب‌های موجود در سیستم
        /// هدف نمایش منوی انتخاب برچسب‌ها از لیست
        /// </summary>
        public string TagsSource { set; get; }

        /// <summary>
        /// آرایه‌ای از برچسب‌های وارد شده توسط کاربر در حین ثبت مطلب
        /// </summary>
        [DisplayName("برچسب‌ها"), Required(ErrorMessage = "*")]
        public string[] Tags { set; get; }

        public int? Id { set; get; }
    }
}
اگر به نام این کلاس دقت کنید، به ViewModel ختم شده است. از این لحاظ که حاوی خواصی می‌باشد که عموما جهت رندر کردن صحیح UI مورد استفاده قرار می‌گیرند و معادلی در سمت بانک اطلاعاتی نخواهند داشت.
افزونه TagIt برای نمایش اطلاعات خود به دو منبع داده نیاز دارد:
الف) TagsSource : لیستی است به فرمت JSON، از هر آنچه که در سیستم پیشتر به عنوان یک برچسب ثبت شده است. از این لیست برای نمایش منوی خودکار انتخاب آیتم‌ها استفاده می‌شود.
ب) InitialTags : لیستی است به فرمت JSON، از تمام برچسب‌های مرتبط با یک مطلب. از این اطلاعات در حین ویرایش یک مطلب استفاده خواهد شد.

در این ViewModel یک خاصیت دیگر به شکل آرایه، به نام Tags تعریف شده است که لیست برچسب‌های وارد شده توسط کاربر را دریافت خواهد کرد.


معرفی کنترلر برنامه

using System.Web.Mvc;
using jQueryMvcSample04.Extensions;
using jQueryMvcSample04.Models;

namespace jQueryMvcSample04.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index(int? id)
        {
            //در ابتدای کار تمام تگ‌های موجود در سیستم از بانک اطلاعاتی دریافت خواهند شد
            //از این تگ‌ها برای تشکیل منوی انتخاب برچسب‌ها استفاده می‌شود
            var tagsSource = new[] { "C#", "C++", "C", "ASP.NET", "MVC" }.ToJson();

            //همچنین صرفا برچسب‌های مطلب جاری که پیشتر ثبت شده‌اند نیز باید از بانک اطلاعاتی دریافت گردند
            //از این برچسب‌ها برای ویرایش یک مطلب موجود استفاده خواهد شد
            var init = new[] { "ASP.NET" }.ToJson();

            var model = new BlogPostViewModel
            {
                TagsSource = tagsSource,
                InitialTags = init,
                Id = id
            };
            return View(model);
        }

        [HttpPost]
        public ActionResult Index(BlogPostViewModel data)
        {
            if (this.ModelState.IsValid)
            {
                //todo: save data
                // ...
                return RedirectToAction(actionName: "index", controllerName: "home");
            }

            //در صورت بروز خطا مجددا اطلاعات موجود نمایش داده خواهند شد
            data.TagsSource = new[] { "C#", "C++", "C", "ASP.NET", "MVC" }.ToJson();
            data.InitialTags = data.Tags.ToJson();
            return View(data);
        }
    }
}


با توجه به توضیحاتی که ارائه شد، کنترلر برنامه ساختار واضح‌تری را یافته است. در اولین بار نمایش صفحه، لیست منبع داده تگ‌ها و همچنین تگ‌های مرتبط با یک مطلب (در صورت وجود) به View ارائه خواهند شد.
از همین ViewModel، در عملیات Post نیز استفاده گردیده و اطلاعات دریافت می‌گردد.
تعریف متد الحاقی ToJson مورد استفاده را نیز در ادامه ملاحظه می‌نمائید:
using System.Linq;
using System.Web.Script.Serialization;

namespace jQueryMvcSample04.Extensions
{
    public static class JsonExt
    {
        public static string ToJson(this string[] initialTags)
        {            
            if (initialTags == null || !initialTags.Any())
                return "[]";
            else
                return new JavaScriptSerializer().Serialize(initialTags);
        }
    }
}

و مرحله آخر تعریف View متناظر است

@model jQueryMvcSample04.Models.BlogPostViewModel
@{
    ViewBag.Title = "Index";
}
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>ثبت مطلب جدید</legend>
        @Html.HiddenFor(model => model.Id)
        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Body)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Body)
            @Html.ValidationMessageFor(model => model.Body)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Tags)
        </div>
        <div class="editor-field">
            <ul id="tagsList" dir="ltr" name="Tags">
            </ul>
            @Html.ValidationMessageFor(model => model.Tags)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
@section JavaScript
{
    <script type="text/javascript">
    $(document).ready(function () {
            var tagsSource = @Html.Raw(Model.TagsSource);
            $('#tagsList').tagit({
                 tagSource: tagsSource, 
                 select: true, 
                 triggerKeys: ['enter', 'comma', 'tab'],
                 initialTags:  @Html.Raw(Model.InitialTags) 
              });
});
    </script>
}
در این View دو نکته حائز اهمیت هستند:
الف) برای نمایش افزونه TagIt از یک ul با id مساوی tagsList استفاده شده است.
ب) خواص اضافی موجود در ViewModel که اطلاعات JSON ایی مورد نیاز را بازگشت می‌دهند در قسمت اسکریپت صفحه مورد استفاده قرار گرفته‌اند. در اینجا نیاز است از Html.Raw استفاده شود تا اطلاعات مرتبط با JSON اشتباها encode نشده و قابل استفاده باشند.

دریافت مثال و پروژه کامل این قسمت
jQueryMvcSample04.zip
مطالب
نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC

همان طور که می‌دانید کاربرد پذیری در خیلی از پروژه‌ها حرف اول رو می‌زند و کاربر دوست دارد کارهایی که انجام می‌دهد خیلی راحت و با استفاده از موس باشد.یکی از کار هایی که در اکثر پروژه‌ها نیاز است ، چیدمان ترتیب رکورد‌ها است. ما می‌خواهیم در این پست ترتیبی اتخاذ کنیم که کاربر بتواند رکورد‌ها را به هر ترتیبی که دوست دارد نمایش دهد.

از توضیحاتی که قبلا  دادم مشخص است که این کار احتمالا در ASP.NET WebForm  کار سختی نیست ولی این کار باید در MVC  از ابتدا طراحی شود.

طرح سوال : یک سری رکورد از یک Table داریم که می‌خواهیم به ترتیب وارد شدن رکورد‌ها نباشد و  ترتیبی که ما می‌خواهیم نمایش داده شود.

پاسخ کوتاه : خب باید ابتدا یک فیلد (برای اولویت بندی)  به Table  اضافه کنیم  بعد اون فیلد رو بنا به ترتیبی که دوست داریم رکورد‌ها نمایش داده شود پر کنیم (Sort  می کنیم ) و در آخر هم هنگام نمایش در View رکورد‌ها را بر اساس این فیلد نمایش می‌دهیم.

(این پست هم در ادامه پست قبلی در همان پروژه است و از همان Table  ها استفاده شده است)

اضافه کردن فیلد :

ابتدا یک فیلد به Table  مورد نظر اضافه می‌کنیم. من اسم این فیلد رو Priority گذاشتم. Table  من چنین وضعیتی دارد.

افزودن فایل‌های jQuery UI :

در این مرحله شما نیاز دارید فایل‌های مورد نیاز برای Sort  کردن رکورد‌ها را اضافه کنید. شما می‌توانید فقط فایل‌های مربوط به Sortable  را به صفحه خودتان اضافه کنید و یا مثل من فایل هایی که حاوی تمام قسمت‌های jQuery UI  هست را اضافه کنید.

من برای این کار از Section  استفاده کردم ، ابتدا در Head  فایل Layout  دو Section  تعریف کردم برای CSS  و JavaScript . و فایل‌های مربوط به Sort کردن را در صفحه ای که باید عمل Sort انجام بشود در  این Section ها قرار دادم.

فایل Layout

<head>
    <meta charset="utf-8" />
    @RenderSection("meta", false)
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/~Site.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/redactor/css/redactor.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/css/bootstrap-rtl.min.css")" rel="stylesheet" type="text/css" />
    @RenderSection("css", false)
    <script src="@Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Content/js/bootstrap-rtl.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Content/redactor/redactor.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
    @RenderSection("js", false)

</head>

فایل Index.chtml  در پوشه کنترلر Type


@model IEnumerable<KhazarCo.Models.Type>
@{
    ViewBag.Title = "Index";
    Layout = "~/Areas/Administrator/Views/Shared/_Layout.cshtml";
}
@section css
{<link href="@Url.Content("~/Content/themes/base/jquery-ui.css")" rel="stylesheet" type="text/css" />
}
@section js
{
    <script src="@Url.Content("~/Scripts/jquery-ui-1.9.0.min.js")" type="text/javascript"></script>
}


در آخر فایل Index.chtml  به اینصورت شده است:

<h2>
    نوع ها</h2>
<p>
    @Html.ActionLink("ایجاد یک مورد جدید", "Create", null, new { @class = "btn btn-info" })
</p>
<table>
    <thead>
        <tr>
            <th>
                عنوان
            </th>
            <th>
                توضیحات
            </th>
            <th>
                فعال
            </th>
            <th>
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.OrderBy(m => m.Priority))
        {
            <tr id="@item.Id">
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @(new HtmlString(item.Description))
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.IsActive)
                </td>
                <td>
                    @Html.ActionLink("ویرایش", "Edit", new { id = item.Id }, new { @class = "btnEdit label label-warning" })
                    |
                    @Html.ActionLink("مشاهده", "Details", new { id = item.Id }, new { @class = "btnDetails label label-info" })
                    |
                    @Html.ActionLink("حذف", "Delete", new { id = item.Id }, new { @class = "btnDelete label label-important" })
                </td>
            </tr>
        }
    </tbody>
</table>

** توجه داشته باشید که من به هر tr  یک id  اختصاص داده ام که این مقدار id  همان مقدار فیلد Id  همان رکورد هست ، ما برای مرتب کردن به این Id  نیاز داریم (خط 25).

افزودن کد‌های کلاینت:

حالا باید کدی بنویسم که دو کار را برای ما انجام دهد : اول حالت Sort  پذیری را به سطر‌های Table  بدهد و دوم اینکه هنگامی که ترتیب سطر‌های تغییر کرد ما را با خبر کند:


<script type="text/javascript">
    $(function () {
        $("table tbody").sortable({
            helper: fixHelper,
            update: function (event, ui) {
                jQuery.ajax('@Url.Action("Sort", "Type", new { area = "Administrator" })', {
                    data: { s: $(this).sortable('toArray').toString() }
                });
            }
        }).disableSelection();
    });
    var fixHelper = function (e, ui) {
        ui.children().each(function () {
            $(this).width($(this).width());
        });
        return ui;
    };
</script>


توضیح کد :

در این کد ما حالت ترتیب پذیری را به Table  می دهیم و هنگامی که عمل Update  در Table  انجام شد تابع مربوطه اجرا می‌شود. ما در این تایع، ترتیب جدید سطر‌ها را می‌گیریم ( ** به کمک مقدار Id  که به هر سطر دادیم ، این مقدار Id  برابر بود با Id خود رکورد در Database )  و به کمکjQuery.ajax  به تابع Sort  از کنترلر Type  در منطقه (area ) Administrator  ارسال می‌کنیم و در آنجا ادامه کار را انجام میدهیم.

تابع fixHelper  هم به ما کمک می‌کند که هنگامی که سطر‌ها از جای خود جدا می‌شوند ، دارای عرض یکسانی باشند و عرض آن‌ها تغییری نکند.


افزودن کد Server:

حالا باید تابع Sort  که مقادیر را به آن ارسال کردیم بنویسم. من این تابع را بر اساس مقداری که از کلاینت ارسال می‌شود اینگونه طراحی کردم.


        public EmptyResult Sort(string s)
        {
            if (s != null)
            {
                var ids = new List<int>();
                foreach (var item in s.Split(','))
                {
                    ids.Add(int.Parse(item));
                }
                int intpriority = 0;

                foreach (var item in ids)
                {
                    intpriority++;
                    db.Types.Single(m => m.Id == item).Priority = intpriority;
                }
                db.SaveChanges();
            }
            return new EmptyResult();
        }

در ایتدا مقادیر Id  که از کلاینت  به صورت String  ارسال شده است را می‌گیریم و بعد به همان ترتیب ارسال در لیستی از int قرار می‌دهیم ids.

سپس به اضای هر رکورد Type  مقدار اولویت را به فیلدی که برای همین مورد اضافه کردیم Priority اختصاص می‌دهیم. و در آخر هم تغییرات را ذخیره می‌کنیم. (خود کد کاملا واضح است و نیاری به توضیح بیشتر نیست )

حالا باید هنگامی که لیست Type  ها نمایش داده می‌شود به ترتیب (OrderBy) فیلد Priority    نمایش داده شود پس تابع Index را اینطور تغییر می‌دهیم.

        public ViewResult Index()
        {
            return View(db.Types.Where(m => m.IsDeleted == false).OrderBy(m => m.Priority));
        }

این هم خروجی کار من:

این عکس مربوط به است به قسمت مدیریت پروژه شیرآلات مرجان خزر


مطالب
LINQ to JSON به کمک JSON.NET
عموما از امکانات LINQ to JSON کتابخانه‌ی JSON.NET زمانی استفاده می‌شود که ورودی JSON تو در توی حجیمی را دریافت کرده‌اید اما قصد ندارید به ازای تمام موجودیت‌های آن یک کلاس معادل را جهت نگاشت به آن‌ها تهیه کنید و صرفا یک یا چند مقدار تو در توی آن جهت عملیات استخراج نهایی مدنظر است. به علاوه در اینجا LINQ to JSON واژه‌ی کلیدی dynamic را نیز پشتیبانی می‌کند.


همانطور که در تصویر مشخص است، خروجی‌های JSON عموما ترکیبی هستند از مقادیر، آرایه‌ها و اشیاء. هر کدام از این‌ها در LINQ to JSON به اشیاء JValue، JArray و JObject نگاشت می‌شوند. البته در حالت JObject هر عضو به یک JProperty و JValue تجزیه خواهد شد.
برای مثال آرایه [1,2] تشکیل شده‌است از یک JArray به همراه دو JValue که مقادیر آن‌را تشکیل می‌دهند. اگر مستقیما بخواهیم یک JArray را تشکیل دهیم می‌توان از شیء JArray استفاده کرد:
 var array = new JArray(1, 2, 3);
var arrayToJson = array.ToString();
و اگر یک JSON رشته‌ای دریافتی را داریم می‌توان از متد Parse مربوط به JArray کمک گرفت:
 var json = "[1,2,3]";
var jArray= JArray.Parse(json);
var val = (int)jArray[0];
خروجی JArray یک لیست از JTokenها است و با آن می‌توان مانند لیست‌های معمولی کار کرد.

در حالت کار با اشیاء، شیء JObject امکان تهیه اشیاء JSON ایی را دارا است که می‌تواند مجموعه‌ای از JPropertyها باشد:
 var jObject = new JObject(
new JProperty("prop1", "value1"),
new JProperty("prop2", "value2")
);
var jObjectToJson = jObject.ToString();
با JObject به صورت dynamic نیز می‌توان کار کرد:
 dynamic jObj = new JObject();
jObj.Prop1 = "value1";
jObj.Prop2 = "value2";
jObj.Roles = new[] {"Admin", "User"};
این روش بسیار شبیه است به حالتی که با اشیاء جاوا اسکریپتی در سمت کلاینت می‌توان کار کرد.
و حالت عکس آن توسط متد JObject.Parse قابل انجام است:
 var json = "{ 'prop1': 'value1', 'prop2': 'value2'}";
var jObj = JObject.Parse(json);
var val1 = (string)jObj["prop1"];

اکنون که با اجزای تشکیل دهنده‌ی LINQ to JSON آشنا شدیم، مثال ذیل را درنظر بگیرید:
 var array = @"[
{
  'prop1': 'value1',
  'prop2': 'value2'
},
{
  'prop1': 'test1',
  'prop2': 'test2'
}
]";
var objects = JArray.Parse(array);
var obj1 = objects.FirstOrDefault(token => (string) token["prop1"] == "value1");
خروجی JArray یا JObject از نوع IEnumerable است و بر روی آن‌ها می‌توان کلیه متدهای LINQ را فراخوانی کرد. برای مثال در اینجا اولین شیءایی که مقدار خاصیت prop1 آن مساوی value1 است، یافت می‌شود و یا می‌توان اشیاء را بر اساس مقدار خاصیتی مرتب کرده و سپس آن‌‌ها را بازگشت داد:
 var values = objects.OrderBy(token => (string) token["prop1"])
.Select(token => new {Value = (string) token["prop2"]})
.ToList();
امکان انجام sub queries نیز در اینجا پیش بینی شده‌است:
 var array = @"[
{
  'prop1': 'value1',
  'prop2': [1,2]
},
{
  'prop1': 'test1',
  'prop2': [1,2,3]
}
]";
var objects = JArray.Parse(array);
var objectContaining3 = objects.Where(token => token["prop2"].Any(v => (int)v == 3)).ToList();
در این مثال، خواص prop2 از نوع آرایه‌ای از اعداد صحیح هستند. با کوئری نوشته شده، اشیایی که خاصیت prop2 آن‌ها دارای عضو 3 است، یافت می‌شوند.
اشتراک‌ها
وبینار برنامه نویسی واکنشی با RxJS

برنامه‌نویسی واکنشی (reactive) یک پارادایم برنامه‌نویسی اظهاری (declarative) است که در آن با جریان (stream)های داده و انتشار تغییرات کار می‌کنیم. این نوع برنامه‌نویسی بیشترین شباهت را به مدارهای سخت‌افزاری دارد. RxJS نمونه موفق و بسیار پرکاربرد Reactive Programming است که در برنامه‌نویسی JavaScript امروزی نقش پر رنگی دارد.

در این وبینار مبانی برنامه‌نویسی واکنشی و RxJS به زبان ساده ارائه می‌شود و پس از آن به چند نمونه از مسائل دنیای واقعی به شکل عملی پرداخته می‌شود. در انتها برخی مباحث پیشرفته‌تر هم عنوان خواهند شد.


زمان برگزاری: یکشنبه  23 آذر، ساعت 18:30 تا 20


محورهای اصلی این وبینار:

  • Introduction to Reactive Programming
  • Observables: Hot/Cold
  • Piping and Operators
  • High Order Observables
  • Advanced Topics
 
وبینار برنامه نویسی واکنشی با RxJS
نظرات مطالب
Protocol Buffers فرمتی برای تبادل دیتا
مقاله جالب و خوبی بود فقط ذکر چند نکته خالی از لطف نیست.
protobuf در مرورگر پشتیبانی نمی‌شود و برای کار با آن می‌توان از  protobuf.js (پیاده سازی Protocol Buffers برای Javascript) استفاده کرد 
برای استفاده از protobuf در دات نت نیز 2 کتابخانه موجود است
1- کتابخانه  Google.Protobuf : که پیاده سازی و استفاده از آن شبیه نسخه اصلی protobuf است. (اطلاعات بیشتر)
2- کتابخانه  protobuf-net : که پیاده سازی و استفاده از آن شبیه بقیه سریالایزر‌های دات نتی بوده و بیشتر متمایل به سی شارپ است. (اطلاعات بیشتر)
به نظرم دومی بیشتر باب میل سی شارپی‌ها باشد و نیز ساده تر. با دیدن مثال هر دو کتابخانه میتوانید بهتر متوجه این تفاوت شوید.
لینک زیر هم به مقایسه این دو کتابخانه پرداخته : 
نظرات مطالب
نحوه استفاده از افزونه Firebug برای دیباگ برنامه‌های ASP.NET مبتنی بر jQuery
حداقل دو علت می‌تونه داشته باشه:
الف) تصاویر رو نمی‌تونه پیدا کنه، یا صفحه کش شده بیش از حد. قسمت «اجرای کدهای jQuery Ajax فوق، چه تغییری را در صفحه سبب می‌شوند؟» را بررسی کنید که چه آدرسی توسط کدهای جی‌کوئری در حال پردازش است.
همچنین کش شدن نتایج قبلی رو هم می‌شود غیرفعال کرد:
$.ajax({
  cache: false /* گاهی از اوقات خصوصا برای آی ایی نیاز است */
});
ب) چند وقت قبل در یکی از بحث‌های سایت دیدم که مورد زیر رعایت نشده بود و کدهای جی‌کوئری کار نمی‌کردند:
<script type="text/javascript">
        $(function () {
            // کدهای جی‌کوئری در اینجا 
        });
</script>
اجرای کدهای جی‌کوئری نیازی به DOM حاضر و آماده دارند که توسط متد document ready آن مانند کدهای فوق باید تدارک دیده شود. نیازی به این کد نخواهد بود اگر اسکریپت‌ها در آخر صفحه و پیش از بسته شدن تگ body اضافه بشن.
اشتراک‌ها
کتابخانه JSIL
JSIL is a compiler that transforms .NET applications and libraries from their native executable format - CIL bytecode - into standards-compliant, cross-browser JavaScript. You can take this JavaScript and run it in a web browser or any other modern JavaScript runtime. Unlike other cross-compiler tools targeting JavaScript, JSIL produces readable, easy-to-debug JavaScript that resembles the code a developer might write by hand, while still maintaining the behavior and structure of the original .NET code.  Demo
کتابخانه JSIL
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 19 - بومی سازی
راه حل توکاری ندارد؛ چون این فناوری سمت سرور است. حتی Razor هم یک فناوری سمت سرور است. بنابراین یا باید وقت بگذارید این روش‌های قدیمی را به جدید ترجمه کنید:
و یا یک تامین کننده‌ی منابع عمومی اسکریپت‌ها را تعریف کنید:
<script type="text/javascript">
if (!window.resourceProvider) {
    window.resourceProvider = {
        message1: '',
        message2: ''
    };
}
</script>
سپس در View باید این کلیدها را بر اساس سرویس سمت سرور بومی سازی، مقدار دهی کنید:
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer

@section Scripts
{
  <script type="text/javascript">
    resourceProvider.message1 = '@Localizer["About Title"]';
  </script> 
}
و در آخر به صورت زیر در هر قسمتی قابل استفاده خواهند بود:
<script type="text/javascript">
   alert(resourceProvider.message1); 
</script>
مطالب
مدیریت پیشرفته‌ی حالت در React با Redux و Mobx - قسمت اول - Redux چیست؟
Redux و Mobx، کتابخانه‌های کمکی هستند برای مدیریت حالت برنامه‌های پیچیده‌ی React. هرچند React به صورت توکار به همراه امکانات مدیریت حالت است، اما این کتابخانه‌ها مزایای ویژه‌ای را به آن اضافه می‌کنند. در این سری ابتدا کتابخانه‌ی Redux را به صورت خالص و مجزای از React بررسی می‌کنیم. از این کتابخانه در برنامه‌های Angular و Ember هم می‌توان استفاده کرد و به صورت اختصاصی برای React طراحی نشده‌است. سپس آن‌را به برنامه‌های React متصل می‌کنیم. در آخر کتابخانه‌ی محبوب دیگری را به نام Mobx بررسی می‌کنیم که برای مدیریت حالت، اصول برنامه نویسی شیءگرا و همچنین Reactive را با هم ترکیب می‌کند و این روزها در برنامه‌های React، بیشتر از Redux مورد استفاده قرار می‌گیرد.


چرا به ابزارهای مدیریت حالت نیاز داریم؟

به محض رد شدن از مرز پیاده سازی امکانات اولیه‌ی یک برنامه، نیاز به ابزارهای مدیریت حالت نمایان می‌شوند؛ خصوصا زمانیکه نیاز است با اطلاعات قابل توجهی سر و کار داشت. مهم‌ترین دلیل استفاده‌ی از یک ابزار مدیریت حالت، مدیریت منطق تجاری برنامه است. منطق نمایشی برنامه مرتبط است به نحوه‌ی نمایش اجزای آن در صفحه؛ مانند نمایش یک صفحه‌ی مودال، تغییر رنگ عناصر با عبور کرسر ماوس از روی آن‌ها و در کل منطقی که مرتبط و یا وابسته‌ی به هدف اصلی برنامه نیست. از سوی دیگر منطق تجاری برنامه مرتبط است با مدیریت، تغییر و ذخیره سازی اشیاء تجاری مورد نیاز آن؛ مانند اطلاعات حساب کاربری شخص و دریافت اطلاعات برنامه از یک API که مختص به برنامه‌ی خاص ما است و به همین دلیل نیاز به ابزاری برای مدیریت بهینه‌ی آن وجود دارد. برای مثال اینکه در کجا باید منطق تجاری و نمایشی را به هم متصل کرد، می‌تواند چالش بر انگیر باشد. چگونه باید اطلاعات کاربر را ذخیره کرد؟ چگونه React باید متوجه شود که اطلاعات ما تغییر کرده‌است و در نتیجه‌ی آن کامپوننتی را مجددا رندر کند؟ یک ابزار مدیریت حالت، تمام این مسایل را به نحو یک‌دستی در سراسر برنامه، مدیریت می‌کند.
اگر از یک ابزار مدیریت حالت استفاده نکنیم، مجبور خواهیم شد تمام اطلاعات منطق تجاری را در داخل state کامپوننت‌ها ذخیره کنیم که توصیه نمی‌شود؛ چون مقیاس پذیر نیست. برای مثال فرض کنید قرار است تمام اطلاعات state را داخل یک کامپوننت ذخیره کنیم. هر زمانیکه بخواهیم این state را از طریق یک کامپوننت فرزند تغییر دهیم، نیاز خواهد بود این اطلاعات را به والد آن کامپوننت ارسال کنیم که اگر از تعداد زیادی کامپوننت تو در تو تشکیل شده باشد، زمانبر و به همراه کدهای تکراری زیادی خواهد بود. همچنین اینکار سبب رندر مجدد کل برنامه با هر تغییری در state آن می‌شود که غیرضروری بوده و کارآیی برنامه را کاهش می‌دهد. به علاوه در این بین مشخص نیست هر قسمت از state، از کدام کامپوننت تامین شده‌است. به همین جهت نیاز به روشی برای مدیریت حالت در بین کامپوننت‌های برنامه وجود دارد.


داشتن تنها یک محل برای ذخیره سازی state در برنامه

همانطور که در قسمت 8 ترکیب کامپوننت‌ها در سری React 16x بررسی کردیم، هر کامپوننت در React، دارای state خاص خودش است و این state از سایر کامپوننت‌ها کاملا مستقل و ایزوله‌است. این مورد با بزرگ‌تر شدن برنامه و برقراری ارتباط بین کامپوننت‌ها، مشکل ایجاد می‌کند. برای مثال اگر بخواهیم دکمه‌ای را در صفحه قرار داده و توسط این دکمه درخواست صفر شدن مقدار هر کدام از شمارشگرها را صادر کنیم، با صفر کردن value هر کدام از این کامپوننت‌ها، اتفاقی رخ نمی‌دهد. چون state محلی این کامپوننت‌ها، با سایر اجزای صفحه به اشتراک گذاشته نمی‌شود و باید آن‌را تبدیل به یک controlled component کرد، بطوریکه دارای local state خاص خودش نیست و تمام داده‌های دریافتی را از طریق this.props دریافت می‌کند و هر زمانیکه قرار است داده‌ای تغییر کند، رخ‌دادی را به والد خود صادر می‌کند. بنابراین این کامپوننت به طور کامل توسط والد آن کنترل می‌شود. تازه این روش در مورد کامپوننت‌هایی صدق می‌کند که رابطه‌ی والد و فرزندی بین آن‌ها وجود دارد. اگر چنین رابطه‌ای وجود نداشت، باید state را به یک سطح بالاتر انتقال داد. برای مثال باید state کامپوننت Counters را به والد آن که کامپوننت App است، منتقل کرد. پس از آن چون کامپوننت‌های ما، از کامپوننت App مشتق می‌شوند، اکنون می‌توان این state را به تمام فرزندان App توسط props منتقل کرد و به اشتراک گذاشت. این مورد هم مانند مثال انتقال اطلاعات کاربر لاگین شده‌ی به سیستم، به تمام زیر قسمت‌های برنامه، نیاز به ارسال اطلاعات از طریق props یک کامپوننت، به کامپوننت بعدی را دارد و به همین ترتیب برای مابقی که به props drilling مشهور است و روش پسندیده‌ای نیست.


Redux چیست؟ ذخیره سازی کل درخت state یک برنامه، در یک محل. به این ترتیب به یک شیء جاوا اسکریپتی بزرگ خواهیم رسید که در برگیرنده‌ی تمام state برنامه‌است. یکی از مزایای آن امکان serialize و deserialize کل این شیء، به سادگی است. برای مثال توسط متد JSON.stringify می‌توان آن‌را در جائی ذخیره کرد و سپس آن‌را به صورت یک شیء جاو اسکریپتی در زمانی دیگر بازیابی کرد. یکی از مزایای آن، امکان بازیابی دقیق شرایط کاربری است که دچار مشکل شده‌است و سپس دیباگ و رفع مشکل او، در زمانی دیگر.


تاریخچه‌ای از سیستم‌های مدیریت حالت

همه چیز با AngularJS 1x شروع شد که از data binding دو طرفه پشتیبانی می‌کرد. هرچند این روش برای همگام نگه داشتن View و مدل برنامه، مفید است، اما در Viewهای پیچیده، برنامه را کند می‌کند. در همین زمان فیس‌بوک، روش مدیریت حالتی را به نام Flux ارائه داد که از data binding یک طرفه پشتیبانی می‌کرد. به این معنا که در این روش، همواره اطلاعات از View به مدل، جریان پیدا می‌کند. کار کردن با آن ساده‌است؛ چون نیازی نیست حدس زده شود که اکنون جریان اطلاعات از کدام سمت است. اما مشکل آن عدم هماهنگی model و view، در بعضی از حالات است. Flux از این جهت به وجود آمد که مدیریت حالت در برنامه‌های React آن زمان، پیچیده بود و مقیاس پذیری کمی داشت (پیش از ارائه‌ی Context و Hooks). در کل Flux صرفا یکسری الگوی مدیریت حالت را بیان می‌کند و یک کتابخانه‌ی مجزا نیست. بر مبنای این الگوها و قراردادها، می‌توان کتابخانه‌های مختلفی را ایجاد کرد. از این رو در سال 2015، کتابخانه‌های زیادی مانند Reflux, Flummox, MartyJS, Alt, Redux و غیره برای پیاده سازی آن پدید آمدند. در این بین، کتابخانه‌ی Redux ماندگار شد و پیروز این نبرد بود!


توابع خالص و ناخالص (Pure & Impure Functions)

پیش از شروع بحث، نیاز است با یک‌سری از واژه‌ها مانند توابع خالص و ناخالص آشنا شد. این نکات از این جهت مهم هستند که Redux فقط با توابع خالص کار می‌کند.
توابع خالص: تعدادی آرگومان را دریافت کرده و بر اساس آن‌ها، مقداری را باز می‌گردانند.
// Pure
const add = (a, b) => {
  return a + b;
}
در اینجا یک تابع خالص را مشاهده می‌کنید که a و b را دریافت کرده و بر این اساس، یک خروجی کاملا مشخص را بازگشت می‌دهد.

توابع ناخالص: این نوع توابع سبب تغییراتی در متغیرهایی خارج از میدان دید خود می‌شوند و یا به همراه یک سری اثرات جانبی (side effects) مانند تعامل با دنیای خارج (وجود یک console.log در آن تابع و یا دریافت اطلاعاتی از یک API خارجی) هستند.
// Impure
const b;

const add = (a) => {
  return a + b;
}
تابع تعریف شده‌ی در اینجا ناخالص است؛ چون با اطلاعاتی خارج از میدان دید خود مانند متغیر b، تعامل دارد. این تعامل با دنیای خارج، حتی در حد نوشتن یک console.log:
// Impure
const add = (a, b) => {
  console.log('lolololol');
  return a + b;
}
یک تابع خالص را تبدیل به یک تابع ناخالص می‌کند و یا نمونه‌ی دیگر این تعاملات، فراخوانی سرویس‌های backend در برنامه هستند که یک تابع را ناخالص می‌کنند:
// Impure
const add = (a, b) => {
   Api.post('/add', { a, b }, (response) => {
    // Do something.
   });
};


روش‌هایی برای جلوگیری از تغییرات در اشیاء در جاوا اسکریپت

ایجاد تغییرات در آرایه‌ها و اشیاء (Mutating arrays and objects) نیز ناخالصی ایجاد می‌کند؛ از این جهت که سبب تغییراتی در دنیای خارج (خارج از میدان دید تابع) می‌شویم. به همین جهت نیاز به روش‌هایی وجود دارد که از این نوع تغییرات جلوگیری کرد:
// Copy object
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original);
برای تغییری در یک شیء، تنها کافی است خاصیتی را به آن اضافه کنیم و یا با استفاده از واژه‌ی کلیدی delete، خاصیتی را از آن حذف کنیم. به همین جهت برای اینکه تغییرات ما بر روی شیء اصلی اثری را باقی نگذارند، یکی از روش‌ها، استفاده از متد Object.assign است. کار آن، یکی کردن اشیایی است که به آن ارسال می‌شوند. به همین جهت در اینجا با یک شیء خالی، از صفر شروع می‌کنیم. سپس دومین آرگومان آن را به همان شیء مدنظر، تنظیم می‌کنیم. به این ترتیب به یک کپی از شیء اصلی می‌رسیم که دیگر به آن، اتصالی را ندارد. به همین جهت اگر بر روی این شیء کپی تغییراتی را ایجاد کنیم، به شیء اصلی کپی نمی‌شود و سبب تغییرات در آن (mutation) نخواهد شد.
برای مثال در React، برای انجام رندر نهایی، در پشت صحنه کار مقایسه‌ی اشیاء صورت می‌گیرد. به همین جهت اگر همان شیءای را که ردیابی می‌کند تغییر دهیم، دیگر نمی‌تواند به صورت مؤثری فقط قسمت‌های تغییر کرده‌ی آن‌را تشخیص داده و کار رندر را فقط بر اساس آن‌ها انجام دهد و مجبور خواهد شد کل یک شیء را بارها و بارها رندر کند که اصلا بهینه نیست. به همین جهت، ایجاد تغییرات مستقیم در شیءای که به state آن انتساب داده می‌شود، مجاز نیست.

متد Object.assign، چندین شیء را نیز می‌تواند با هم یکی کند و شیء جدیدی را تشکیل دهد:
// Extend object
const original = { a: 1, b: 2 };
const extension = { c: 3 };
const extended = Object.assign({}, original, extension);
روش دیگر ایجاد یک کپی و یا clone از یک شیء را که پیشتر در سری «React 16x» بررسی کردیم، به کمک امکانات ES-6، به صورت زیر است:
// Copy object
const original = { a: 1, b: 2 };
const copy = { ...original };
در اینجا نیز ابتدا یک شیء خالی را ایجاد می‌کنیم و سپس توسط spread operator، خواص شیء قبلی را درون آن باز کرده و قرار می‌دهیم. به این ترتیب به یک clone از شیء اصلی می‌رسیم. این حالت نیز از ترکیب چندین شیء با هم، پشتیبانی می‌کند:
// Extend object
const original = { a: 1, b: 2 };
const extension = { c: 3 };
const extended = { ...original, ...extension };


روش‌هایی برای جلوگیری از تغییرات در آرایه‌ها در جاوا اسکریپت

متد slice آرایه‌ها نیز بدون ذکر آرگومانی، یک کپی از آرایه‌ی اصلی را ایجاد می‌کند:
// Copy array
const original = [1, 2, 3];
const copy = [1, 2, 3].slice();
همچنین معادل همین قطعه کد در ES-6 به همراه spread operator به صورت زیر است:
// Copy array
const original = [1, 2, 3];
const copy = [ ...original ];
و یا اگر بخواهیم یک کپی از چندین آرایه را ایجاد کنیم می‌توان از متد concat استفاده کرد:
// Extend array
const original = [1, 2, 3];
const extended = original.concat(4);
const moreExtended = original.concat([4, 5]);
متد Array.push، هرچند سبب افزوده شدن عنصری به یک آرایه می‌شود، اما یک mutation را نیز ایجاد می‌کند؛ یعنی تغییرات آن به دنیای خارج اعمال می‌گردد. اما Array.concat یک آرایه‌ی کاملا جدید را ایجاد می‌کند و همچنین امکان ترکیب آرایه‌ها را نیز به همراه دارد.
معادل قطعه کد فوق در ES-6 و به همراه spread operator آن به صورت زیر است:
// Extend array
const original = [1, 2, 3];
const extended = [ ...original, 4 ];
const moreExtended = [ ...original, ...extended, 5 ];


مفاهیم ابتدایی Redux


در Redux برای ایجاد تغییرات در شیء کلی state، از مفهومی به نام dispatch actions استفاده می‌شود. action در اینجا به معنای رخ‌دادن چیزی است؛ مانند کلیک بر روی یک دکمه و یا دریافت اطلاعاتی از یک API. در این حالت مقایسه‌ای بین وضعیت قبلی state و وضعیت فعلی آن صورت می‌گیرد و تغییرات مورد نیاز جهت اعمال به UI، محاسبه خواهند شد.
اصلی‌ترین جزء Redux، تابعی است به نام Reducer. این تابع، یک تابع خالص است و دو آرگومان را دریافت می‌کند:


تابع Reducer، بر اساس action و یا رخ‌دادی، ابتدا کل state برنامه را دریافت می‌کند و سپس خروجی آن بر اساس منطق این تابع، یک state جدید خواهد بود. اکنون که این state جدید را داریم، برنامه‌ی React ما می‌تواند به تغییرات آن گوش فرا داده و بر اساس آن، UI را به روز رسانی کند. به این ترتیب کار اصلی مدیریت state، به خارج از برنامه‌ی React منتقل می‌شود.

در این تصویر، تابع action creator را هم ملاحظه می‌کند که کاملا اختیاری است. یک action می‌تواند یک رشته و یا یک عدد باشد. با پیچیده شدن برنامه، نیاز به ارسال یک‌سری متادیتا و یا اطلاعات بیشتری از اکشن رسیده‌است. کار action creator، ایجاد شیء action، به صورت یک دست و یکنواخت است تا دیگر نیازی به ایجاد دستی آن نباشد.


مزایای کار با Redux

- داشتن یک مکان مرکزی برای ذخیره سازی کلی حالت برنامه (به آن «source of truth» و یا store هم گفته می‌شود): به این ترتیب مشکل ارسال خواص در بین کامپوننت‌های عمیق و چند سطحی، برطرف شده و هر زمانیکه نیاز بود، از آن اطلاعاتی را دریافت و یا با قالب خاصی، آن‌را به روز رسانی می‌کنند.
- رسیدن به به‌روز رسانی‌های قابل پیش بینی state: هرچند در حالت کار با Redux، یک شیء بزرگ جاوا اسکریپتی، کل state برنامه را تشکیل می‌دهد، اما امکان کار مستقیم با آن و تغییرش وجود ندارد. به همین جهت است که برای کار با آن، باید رویدادی را از طریق actionها به تابع Reducer آن تحویل داد. چون Reducer یک تابع خالص است، با دریافت یک سری ورودی مشخص، همواره یک خروجی مشخص را نیز تولید می‌کند. به همین جهت قابلیت ضبط و تکرار را پیدا می‌کند؛ همان بحث serialize و deseriliaze، توسط ابزاری مانند: logrocket. به علاوه قابلیت undo و redo را نیز می‌توان به این ترتیب پیاده سازی کرد (state جدید محاسبه شده، مشخص است، کل state قبلی را نیز داریم یا می‌توان ذخیره کرد و سپس برای undo، آن‌را جایگزین state جدید نمود). افزونه‌ی redux dev tools نیز قابلیت import و export کل state را به همراه دارد.
- چون تابع Reducer، یک تابع خالص است و همواره خروجی‌های مشخصی را به ازای ورودی‌های مشخصی، تولید می‌کند، آزمایش کردن، پیاده سازی و حتی logging آن نیز ساده‌تر است. در این بین حتی یک افزونه‌ی مخصوص نیز برای دیباگ آن تهیه شده‌است: redux-devtools-extension. تابع خالص، تابعی است که به همراه اثرات جانبی نیست (side effects)؛ به همین جهت عملکرد آن کاملا قابل پیش بینی بوده و آزمون پذیری آن به دلیل نداشتن وابستگی‌های خارجی، بسیار بالا است.


Context API خود React چطور؟

در قسمت 33 سری React 16x، مفهوم React Context را بررسی کردیم. پس از معرفی آن با React 16.3، مقالات زیادی منتشر شدند که ... Redux مرده‌است (!) و یا بجای Redux از React context استفاده کنید. اما واقعیت این است که React Redux در پشت صحنه از React context استفاده می‌کند و تابع connect آن دقیقا به همین زیر ساخت متصل می‌شود.
کار با Redux مزایایی مانند کارآیی بالاتر، با کاهش رندر‌های مجدد کامپوننت‌ها، دیباگ ساده‌تر با افزونه‌های اختصاصی و همچنین سفارشی سازی، مانند نوشتن میان‌افزارها را به همراه دارد. اما شاید واقعا نیازی به تمام این امکانات را هم نداشته باشید؛ اگر هدف، صرفا انتقال ساده‌تر اطلاعات بوده و برنامه‌ی مدنظر نیز کوچک است. React Context برخلاف Redux، نگهدارنده‌ی state نیست و بیشتر هدفش محلی برای ذخیره سازی اطلاعات مورد استفاده‌ی در چندین و چند کامپوننت تو در تو است. هرچند شبیه به Redux می‌توان اشاره‌گرهایی از متدها را به استفاده کنندگان از آن ارسال کرد تا سبب بروز رویدادها و اکشن‌هایی در کامپوننت تامین کننده‌ی Contrext شوند (یا یک کتابخانه‌ی ابتدایی شبیه به Redux را توسط آن تهیه کرد). بنابراین برای انتخاب بین React Context و Redux باید به اندازه‌ی برنامه، تعداد نفرات تیم، آشنایی آن‌ها با مفاهیم Redux دقت داشت.
نظرات مطالب
معرفی List Patterns Matching در C# 11
تبدیل کدهایی که از اندیس‌های آرایه‌ها استفاده می‌کنند به List Patterns matching

فرض کنید قصد داریم با اجزای آرایه‌ی زیر کار کنیم:
var data = "item1|item2|item3";
var collection = data.Split('|');
برای مثال اگر آرایه‌ی collection دارای 2 عضو بود، از طریق collection[0], collection[1] با این دو عضو کار کنیم و یا اگر 3 عضوی بود، به همان صورت بر اساس ایندکس‌ها دسترسی صورت گیرد و اگر این آرایه 2 و یا 3 عضوی نبود، استثنایی را صادر کند. روش متداول انجام اینکار به صورت زیر است:
var formattedDataBefore = collection.Length switch
{
    2 => FormatData(collection[0], collection[1]),
    3 => FormatData(collection[0], collection[1], collection[2]),
    var length => throw new InvalidOperationException($"Expected 3 parts, but got {length} parts for formatted string: {data}."),
};
می‌توان این قطعه کد را با استفاده از List Patterns Matching به صورت زیر بازنویسی کرد:
var formattedDataAfter = collection switch
{
    [var part1, var part2] => FormatData(part1, part2),
    [var part1, var part2, var part3] => FormatData(part1, part2, part3),
    var parts => throw new InvalidOperationException($"Expected 3 parts, but got {parts.Length} parts for formatted string: {data}."),
};

نمونه‌ی دیگر این دسترسی‌های بر اساس ایندکس‌ها، مثال زیر است. در اینجا ساختار شیء Song به صورت زیر تعریف شده‌است:
public class Song
{
    public string Name { get; set; }
    public List<string> Lyrics { get; set; }
}
و فرض کنید songs لیستی از آن است. در این حالت یک روش جستجوی ابتدایی در این لیست، به صورت زیر است که برای مثال اولین Lyrics آن song خاص، مساوی Hello، تعداد Lyrics آن 6 و آخرین عضو Lyrics آن مساوی ? باشد:
for (var i = 0; i < songs.Count; i++)
{
    if (songs[i].Lyrics[0] == "Hello" && songs[i].Lyrics.Count == 6 &&
        songs[i].Lyrics[songs[i].Lyrics.Count - 1] == "?")
    {
        Console.WriteLine($"{i}");
    }
}
می‌توان این قطعه کد را در C# 11 به صورت زیر بازنویسی کرد که بسیار خواناتر است:
for (var i = 0; i < songs.Count; i++)
{
    if (songs[i].Lyrics is ["Hello", _, _, _, _, "?"])
    {
       Console.WriteLine($"{i}");
    }
}
و یا اگر از تعداد Lyrics مساوی 6، صرفنظر کنیم و تعداد اعضای آن مهم نباشد، می‌توان به صورت زیر عمل کرد:
foreach (Song song in songs)
{
    if (song.Lyrics is ["Hello", .., "?"])
    {
        Console.WriteLine(song.Name);
    }
}

به علاوه اگر در جستجویی دیگر، نیاز به کار با اعضای آرایه‌ی 5 عضوی یافت شده وجود داشت، می‌توان بدون نیاز به مراجعه‌ی متداول به ایندکس‌های آرایه، به صورت زیر عمل کرد:
foreach (Song song in songs)
{
  if (song.Lyrics is ["Hello", "from" or "is", var third, var forth, var fifth])
    {
      Console.WriteLine(song.Name);
      Console.WriteLine($"The third word is : {third}");
      Console.WriteLine($"The forth word is : {forth}");
      Console.WriteLine($"The fifth word is : {fifth}");
    }
}