دات نت 6 دارای بهبودهای بسیار زیادی است که احتمالا برخی از آنها را از دست داده اید، در این مطلب درباره ویژگی های جذاب دات نت 6 صحبت می کنیم.
زمانی که دات نت 6 در ماه نوامبر امسال منتشر شد برخی از ویژگی های برتر آن توجه همه را به خود جلب کرد. درباره پشتیبانی از سی شارپ 10، hot reload، کامپایل AOT که متعلق به Blazor است و همینطور برخی از بهبودهای جدی در عملکرد حلقه صحبت های زیادی شده است ولی اگر کمی فراتر از آن به نسخه 6 دات نت نگاه کنیم می بینیم که اصلاحات کوچک ولی ارزشمندی نیز به وجود آمده اند که برنامه نویسی مداوم را برای شما قابل تحمل تر می کنند. ما در ادامه این مطلب قصد داریم به بررسی این ویژگی ها و امکانات دات نت 6 بپردازیم.
بررسی ساده پارامتر null در دات نت 6
هیچکس تا به حال برای null-parameter check یا بررسی پارامتر null در بالای متدها مشکلی نداشته است ولی این مورد به قدری مکررا استفاده می شود که حتی زبان برنامه نویسی سی شارپ نیز به دنبال خودکارسازی آن می باشد و در حال آزمایش روشی برای انجام این کار است. چیزی که در عوض به دست می آوریم یک متد helper است که به شکل زیر کدها را تغییر می دهد:
public UpdateAddress(int personId, Address newAddress)
{
if (newAddress == null)
{
throw new ArgumentNullException("newAddress");
}
...
}
کدهای بالا به کدهای پایین تبدیل می شوند:
public UpdateAddress(int personId, Address newAddress)
{
ArgumentNullException.ThrowIfNull(newAddress);
...
}
این عملیات یک عملیات جادویی نیست اما چنین بهبود جزئی در خوانایی کدها زمانی اهمیت پیدا می کند که شما یک پایگاه کد عظیم داشته باشید و یک اشتباه تایپی کوچک از اجرای کدهای شما جلوگیری می کند.
جدا کردن تاریخ و زمان
اگر از دوره TimeSpan.Zero با دات نت کدنویسی می کنید احتمالا با ساختار ذخیره تاریخ و ساعت در آن آشنایی دارید که به صورت دقیق تاریخ و ساعت را ذخیره می کند. احتمالا شما از قطعه کدی مشابه زیر برای این کار استفاده می کردید:
DateTime dateValue = someDateFunction();
DateTime dateOnly = dateValue.Date;
این قطعه کد به درستی کار می کند اما همیشه این احتمال وجود دارد که شما فراموش کنید مقدار زمان را حذف کنید که می تواند محاسبات و مقایسه تاریخ ها را بهم بزند. علاوه بر این مشکلات مقایسه دیگری نیز در این قطعه کد وجود دارد که در زمان مقایسه دو شی ممکن است چالش های جدی را برای شما به وجود بیاورد. دات نت 6 نهایتا این حفره را به ساده ترین شکل ممکن برطرف کرده است که این کار با استفاده از انواع داده TimeOnly و DateOnly که تنها بخشی از DateTime هستند صورت می گیرد. استفاده از آنها در کدها بسیار ساده بوده و به شکل زیر انجام می شود:
// Make a DateOnly explicitly (for Jan 20, 2022)
DateOnly d1 = new DateOnly(2022, 1, 20);// Make a DateOnly from a DateTime
DateOnly d2 = DateOnly.FromDateTime(dateValue);// Make a TimeOnly explicitly (at 3:30 PM)
TimeOnly t1 = new TimeOnly(15, 30);// Combine a DateOnly and a TimeOnly
DateTime dtCombined = d1.ToDateTime(t1);// Convert a DateOnly to a DateTime (at 12:00 AM)
DateTime dtCopy = d1.ToDateTime(new TimeOnly(0,0));
البته باید دقت داشته باشید که انواع داده DateOnly و TimeOnly از همان ویژگی ها و متدهای DateTime نیز پشتیبانی می کنند.
مایکروسافت امروزه به میزان زیادی روی این مسئله در دات نت 6 متمرکز شده است تا بتواند این مشکل توسعه دهندگان را برطرف کند.
ایجاد صف اولویت در دات نت 6
احتمالا همه ما با مجموعه داده های Stack یا پشته آشنا هستیم که جزء مجموعه داده های LIFO به شمار می آیند (آخرین عنصر اضافه شده اولین عنصری است که بررسی می شود). علاوه بر این مجموعه داده های صف را نیز می شناسیم که FIFO هستند یعنی اولین عنصری که اضافه شود اولین عنصری است که بررسی می شود. با این حال صف های اولویت متفاوت از این دو عمل می کنند و هر یک از عناصر آنها دارای اولویت و درجه اهمیت مخصوص به خود هستند. ساده ترین راه برای پیاده سازی آنها استفاده از یک عدد صحیح است که نشان دهنده درجه اهمیت آنها می باشد. این کار را می توان به شکل زیر انجام داد:
// Fill the queue
var queue = new PriorityQueue<string, int>();
queue.Enqueue("Item with priority 2", 2);
queue.Enqueue("Item with priority 1", 1);
queue.Enqueue("Item with priority 3", 3);// Get out all the items out
while (queue.TryDequeue(out string item, out int priority))
{
Console.WriteLine(item);
}
زمانی که شما این قطعه کد را اجرا می کنید ابتدا عناصری که کمترین اولویت عددی را دارند دریافت می کنید. بنابراین ترتیب اولویت 1، 2 و 3 خواهد بود و نحوه درج عناصر اهمیتی ندارد. به جای استفاده از عدد صحیح می توان این عناصر را با تاریخ و رشته نیز اولویت بندی کرد. علاوه بر این شما می توانید مرتب سازی سفارشی نیز روی این داده ها انجام دهید. مثال زیر را در نظر بگیرید:
public class ProjectComparer: IComparer<ProjectStatus>
{
public int Compare(ProjectStatus a, ProjectStatus b)
{
// Compare two ProjectStatus objects based on the due dates.
return a.Due.CompareTo(b.Due);
}
}public class ProjectStatus
{
public int Status {get; set;}
public DateOnly Due {get; set;}
}
در ادامه شما می توانید در زمان ساخت یک صف اولویت از ProjectComparer استفاده کنید.
var queue = new
PriorityQueue<ProjectData, ProjectStatus>(new ProjectComparer());
رمزنگاری ساده برای داده های کوچک
رمزگذاری و رمزنگاری یکی از مواردی است که شما همیشه به صورت غیرمستقیم از آن استفاده می کنید اما به ندرت پیش می آید که مجبور شوید تا به صورت مستقیم از آن استفاده کنید. در مواقعی که شما نیازمند رمزنگاری داده های خود هستید دات نت همیشه می تواند مشکلات و چالش هایی را برای شما به همراه داشته باشد. در واقع شما باید بیشتر از آنچه که انتظار می رود کدنویسی کنید حتی اگر قصد داشته باشید داده های بسیار کوچک را رمزگذاری کنید. در دات نت 6 این کار بسیار ساده تر شده است و شما برای رمزنگاری مجموعه داده های کوچک کار ساده ای را پیش رو خواهید داشت. برای انجام این کار شما می توانید از متد ()Aes.EncryptCbc استفاده کنید که یک بلوک کامل از بایت ها را برای شما رمزنگاری می کند.
byte[] data = default;
using (Aes aes = Aes.Create())
{
aes.Key = ...
byte[] iv = ... // One shot encryption
byte[] encrypted = aes.EncryptCbc(data, iv);
}
نکاتی درباره قطعه کد بالا
برای استفاده از این قابلیت شما حداقل باید با نحوه ایجاد و مدیریت یک کلید رمزنگاری متقارن و بردارهای اولیه آشنایی داشته باشید. در صورتی که این دانش را نداشته باشید نمی توانید از آن استفاده کنید. در صورتی که بخواهید عکس این عملیات را انجام دهید می توانید از ()DecryptCbc استفاده کنید که به همین منظور طراحی شده است.
تولید اعداد تصادفی رمزنگاری شده در کمترین زمان
دات نت 6 دارای چند ابزار کاربردی دیگر در زمینه رمزنگاری است که با الگوریتم های هش مختلف کار می کنند و باعث صرفه جویی در کدهای شما می شوند. ()RandomNumberGenerator.GetBytes یکی از بهترین ابزارهایی است که در این زمینه وجود دارد و برای تولید اعداد تصادفی رمزنگاری شده در دات نت 6 مورد استفاده قرار می گیرد. این متد می تواند یک آرایه از بایت ها را با اعداد شبه تصادفی قوی از نظر رمزنگاری پر کند. نحوه استفاده از آن به شکل زیر است:
byte[] randomBytes = RandomNumberGenerator.GetBytes(100);
شما در صورت نیاز می توانید این آرایه از بایت ها را به سایر انواع داده نیز تبدیل کنید که این کار به شکل زیر انجام می شود:
byte[] randomBytes = RandomNumberGenerator.GetBytes(4);
int randomInt = BitConverter.ToInt32(randomBytes);
افزودن Chunk در LINQ در دات نت 6
در دات نت 6 زمانی که یک کوئری LINQ می تواند مشکلات را به شکل ظریف تر و بهتری حل کند استفاده از راهکارهای دیگر چندان منطقی به نظر نمی رسد. با این حال امروزه LINQ یک اکستنشن متد جدید به نام ()Chunk را ارائه داده است که راهکاری ساده را برای تبدیل یک مجموعه به زیرمجموعه های کوچتر در اختیار شما قرار میدهد. این متد برای واکشی دسته ای از اقلام از یک مجموعه queryable مورد استفاده قرار می گیرد. اگر شما هم پیش از این با متدهایی مانند ()Skip یا ()Take کار کرده اید احتمالا از این متد نیز راضی خواهید بود و استفاده از آن یک تجربه مناسب برای شما خواهد بود. به عنوان مثال قطعه کد زیر را در نظر بگیرید:
// Let's try this out with a collection of 100 random numbers
var numbers = new List<int>();
for (int i=0; i<100; i++)
{
var rand = new Random();
numbers.Add(rand.Next(1, 100));
}// We'll grab ten numbers at a time
var chunkSize = 10;
// Grab just one chunk
foreach(var chunk in numbers.Chunk(chunkSize))
{
Console.WriteLine("New chunk");
foreach(var item in chunk)
{
Console.WriteLine(item);
}
}
خروجی کامل قطعه کد بالا چیزی شبیه به خروجی زیر خواهد بود:
New chunk
923
809
842
51
478
50
554
710
327
604
New chunk
996
600
373
889
433
513
494
721
339
757
New chunk
700
920
371
...
همانطور که مشاهده می کنید کار کردن با آن بسیار ساده و راحت خواهد بود.
قابلیت Asynchronous waiting با یک فاصله زمانی در دات نت 6
اگر شما هم یک کاربر معمولی Task API دات نت هستید احتمالا می دانید که وظایفی که اجرا شدن آنها مدت زمان زیادی طول می کشد باید از قابلیت لغو شدن پشتیبانی کنند ولی گاهی اوقات آنها از این قابلیت پشتیبانی نمی کنند. راهکارهای مختلفی برای غلبه کردن بر این محدودیت وجود دارد ولی در دات نت 6 یک متد ()WaitAsync بسیار مفید و کاربردی وجود دارد که دارای یک مدت زمان داخلی نیز می باشد. زمانی که یک وظیفه در کدهای شما کامل نمی شود و مدت زمان اجرای آن نیز به پایان می رسد آن وظیفه ادامه پیدا می کند ولی کد شما منتظر آن باقی نمی ماند و بخش های دیگری از کد امتحان می شود. به عنوان مثال قطعه کد زیر را در نظر بگیرید:
// Wait up to 30 seconds for this task:
await someTask.WaitAsync(TimeSpan.FromSeconds(30));
موازی سازی آسان در نسخه 6 دات نت
()ForEachAsync یک متد کوچک ولی هوشمندانه در دات نت 6 است که می تواند کاربردهای بسیار زیادی را برای شما به همراه داشته باشد. در مثال زیر نحوه کار با این متد را مشاهده می کنید:
using System.Net.Http.Headers;
using System.Net.Http.Json;var userHandlers = new []
{
"users/okyrylchuk",
"users/shanselman",
"users/jaredpar",
"users/davidfowl"
};using HttpClient client = new()
{
BaseAddress = new Uri("https://api.github.com"),
};client.DefaultRequestHeaders.UserAgent.Add(
new ProductInfoHeaderValue("DotNet", "6"));ParallelOptions parallelOptions = new()
{
MaxDegreeOfParallelism = 3
};await Parallel.ForEachAsync(userHandlers, parallelOptions,
async (uri, token) =>
{
var user =
await client.GetFromJsonAsync<GitHubUser>(uri, token);
Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}\n");
});public class GitHubUser
{
public string Name { get; set; }
public string Bio { get; set; }
}
این متد در واقع مجموعه ای از وظایف را راه اندازی می کند که به طور همزمان انجام می شوند (در این مثال این کار با استفاده از ویژگی MaxDegreeOfParallelism انجام می شود). اگر شما چندین عملیات جداگانه دارید که برای اجرا شدن به یکدیگر وابسته نیستند می توانید از این قابلیت در دات نت 6 استفاده کرده و نهایت بهره را از آن ببرید.
برای بررسی برخی از ویژگی های دیگر دات نت 6 می توانید به آموزش رایگان ویژگی های جدید در C# 10 / .NET 6 رجوع کنید.
نظرات کاربران در رابطه با این دوره