کتاب Akka.NET مختصر و مفید
Akka.NET is an open-source actor model framework written exclusively for
Microsoft.NET in C# and compatible with .NET Core. It simplifies the
building of scalable, concurrent, high-throughput, and low-latency
systems, making life for software developers a bit easier. Zoran
Maksimovic's Akka.NET Succinctly will show readers what an actor
model is and how to work with actors in Akka.NET, taking them from an
actor's lifecycle through to unit testing.
1. Easily acquire all your Android platform needs
2. Jump start your Android development with C++ cross-platform templates and samples
3. One C++ IDE to target all mobile platforms (iOS, Android, Windows and more)
4. Leverage powerful cross-platform coding tools
5. Share your cross-platform C++ code easily
6. Fastest C++ builds with Incredibuild support
7. The fastest and most robust debugging experience for your Android application
8. Leverage the best in Breed, free Android Emulator
9. Gather your application insights easily using HockeyApp
10. Visual Studio is the cross-platform mobile solution (Xamarin, Apache Cordova) and just not limited to cross-platform C++
نکات کار با استثناءها در دات نت
System.InvalidOperationException: Collection was modified; enumeration operation may not execute. . . . at Program.<>c__DisplayClass8_0.<Method>b__0()
_logger.LogError(ex.Demystify(), "Invalid operation.");
چرا در C# 9.0 تا این اندازه بر روی سادگی ایجاد اشیاء Immutable تمرکز شدهاست؟
به شیءای Immutable گفته میشود که پس از وهله سازی ابتدایی آن، وضعیت آن دیگر قابل تغییر نباشد. همچنین به کلاسی Immutable گفته میشود که تمام وهلههای ساخته شدهی از آن نیز Immutable باشند. نمونهی یک چنین شیءای را از نگارش 1 دات نت در حال استفاده هستیم: رشتهها. رشتهها در دات نت غیرقابل تغییر هستند و هرگونه تغییری بر روی آنها، سبب ایجاد یک رشتهی جدید (یک شیء جدید) میشود. نوع جدید record نیز به همین صورت عمل میکند.
مزایای وجود Immutability:
- اشیاء Immutable یا غیرقابل تغییر، thread-safe هستند که در نتیجه، برنامه نویسی همزمان و موازی را بسیار ساده میکنند؛ چون چندین thread میتوانند با شیءای کار کنند که دسترسی به آن، تنها read-only است.
- اشیاء Immutable از اثرات جانبی، مانند تغییرات آنها در متدهای مختلف در امان هستند. میتوانید آنها را به هر متدی ارسال کنید و مطمئن باشید که پس از پایان کار، این شیء تغییری نکردهاست.
- کار با اشیاء Immutable، امکان بهینه سازی حافظه را میسر میکنند. برای مثال NET runtime.، هش رشتههای تعریف شدهی در برنامه را در پشت صحنه نگهداری میکند تا مطمئن شود که تخصیص حافظهی اضافی، برای رشتههای تکراری صورت نمیگیرد. نمونهی دیگر آن نمایش حرف "a" در یک ادیتور یا نمایشگر است. زمانیکه یک شیء Immutable حاوی اطلاعات حرف "a"، ایجاد شود، به سادگی میتوان این تک وهله را جهت نمایش هزاران حرف "a" مورد استفادهی مجدد قرار داد، بدون اینکه نگران مصرف حافظهی بالای برنامه باشیم.
- کار با اشیاء Immutable به باگهای کمتری ختم میشود؛ چون همواره امکان تغییر حالت درونی یک شیء، توسط قسمتهای مختلف برنامه، میتواند به باگهای ناخواستهای منتهی شوند.
- Hash listها که در جهت بهبود کارآیی برنامهها بسیار مورد استفاده قرار میگیرند، بر اساس کلیدهایی Immutable قابل تشکیل هستند.
روش تعریف نوعهای جدید record
کلاس سادهی زیر را در نظر بگیرید:
public class User { public string Name { set; get; } }
public record User { public string Name { set; get; } }
var user = new User(); user.Name = "User 1";
روش تعریف دومی نیز در اینجا میسر است (به آن positional record هم میگویند):
public record User(string Name);
برای کار با رکورد دومی که تعریف کردیم باید سازندهی این record را مقدار دهی کرد:
var user = new User("User 1"); // Error: Init-only property or indexer 'User.Name' can only be assigned // in an object initializer, or on 'this' or 'base' in an instance constructor // or an 'init' accessor. [CS9Features]csharp(CS8852) user.Name = "User 1";
نوع جدید record چه اطلاعاتی را به صورت خودکار تولید میکند؟
روش دوم تعریف recordها اگر در نظر بگیریم:
public record User(string Name);
using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; using CS9Features; public class User : IEquatable<User> { protected virtual Type EqualityContract { [System.Runtime.CompilerServices.NullableContext(1)] [CompilerGenerated] get { return typeof(User); } } public string Name { get; set/*init*/; } public User(string Name) { this.Name = Name; base..ctor(); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("User"); stringBuilder.Append(" { "); if (PrintMembers(stringBuilder)) { stringBuilder.Append(" "); } stringBuilder.Append("}"); return stringBuilder.ToString(); } protected virtual bool PrintMembers(StringBuilder builder) { builder.Append("Name"); builder.Append(" = "); builder.Append((object?)Name); return true; } [System.Runtime.CompilerServices.NullableContext(2)] public static bool operator !=(User? r1, User? r2) { return !(r1 == r2); } [System.Runtime.CompilerServices.NullableContext(2)] public static bool operator ==(User? r1, User? r2) { return (object)r1 == r2 || (r1?.Equals(r2) ?? false); } public override int GetHashCode() { return EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name); } public override bool Equals(object? obj) { return Equals(obj as User); } public virtual bool Equals(User? other) { return (object)other != null && EqualityContract == other!.EqualityContract && EqualityComparer<string>.Default.Equals(Name, other!.Name); } public virtual User <Clone>$() { return new User(this); } protected User(User original) { Name = original.Name; } public void Deconstruct(out string Name) { Name = this.Name; } }
- recordها هنوز هم در اصل همان classهای استاندارد #C هستند (یعنی در اصل reference type هستند).
- این کلاس به همراه یک سازنده و یک خاصیت init-only است (بر اساس تعاریف ما).
- متد ToString آن بازنویسی شدهاست تا اگر آنرا بر روی شیء حاصل، فراخوانی کردیم، به صورت خودکار نمایش زیبایی را از محتوای آن ارائه دهد.
- این کلاس از نوع <IEquatable<User است که امکان مقایسهی اشیاء record را به سادگی میسر میکند. برای این منظور متدهای GetHashCode و Equals آن به صورت خودکار بازنویسی و تکمیل شدهاند (یعنی مقایسهی آن شبیه به value-type است).
- این کلاس امکان clone کردن اطلاعات جاری را مهیا میکند.
- همچنین به همراه یک متد Deconstruct هم هست که جهت انتساب خواص تعریف شدهی در آن، به یک tuple مفید است.
بنابراین یک رکورد به همراه قابلیتهایی است که سالها در زبان #C وجود داشتهاند و شاید ما به سادگی حاضر به تشکیل و تکمیل آنها نمیشدیم؛ اما اکنون کامپایلر زحمت کدنویسی خودکار آنها را متقبل میشود!
ساخت یک وهلهی جدید از یک record با clone کردن آن
اگر به کدهای حاصل از دیکامپایل فوق دقت کنید، یک قسمت جدید clone هم با syntax خاصی در آن ظاهر شدهاست:
public virtual User <Clone>$() { return new User(this); }
public record User(string Name, int Age);
var user1 = new User("User 1", 21);
var user2 = user1 with { Age = 31 };
مقایسهی نوعهای record
در کدهای حاصل از دیکامپایل فوق، قسمت عمدهای از آن به تکمیل اینترفیس <IEquatable<User پرداخته شده بود. به همین جهت اکنون دو رکورد با مقادیر خواص یکسانی را ایجاد میکنیم:
var user1 = new User("User 1", 21); var user2 = new User("User 1", 21);
Console.WriteLine("user1.Equals(user2) -> {0}", user1.Equals(user2)); Console.WriteLine("user1 == user2 -> {0}", user1 == user2);
user1.Equals(user2) -> True user1 == user2 -> True
- زمانیکه عملگر == را بر روی شیء user1 و user2 اعمال میکنیم، اگر User، از نوع کلاس معمولی باشد، حاصل آن false خواهد بود؛ چون این دو، به یک مکان از حافظه اشاره نمیکنند، حتی با اینکه مقادیر خواص هر دو شیء یکی است.
- اما اگر به قطعه کد دیکامپایل شده دقت کنید، در یک رکورد که هر چند در اصل یک کلاس است، حتی عملگر == نیز بازنویسی شدهاست تا در پشت صحنه همان متد Equals را فراخوانی کند و این متد با توجه به پیاده سازی اینترفیس <IEquatable<User، اینبار دقیقا مقادیر خواص رکورد را یک به یک مقایسه کرده و نتیجهی حاصل را باز میگرداند:
public virtual bool Equals(User? other) { return (object)other != null && EqualityContract == other!.EqualityContract && EqualityComparer<string>.Default.Equals(Name, other!.Name) && EqualityComparer<int>.Default.Equals(Age, other!.Age); }
یک نکته: بازنویسی عملگر == در SDK نگارش rc2 فعلی رخدادهاست و در نگارشهای قبلی preview، اینگونه نبود.
امکان ارثبری در recordها
دو رکورد زیر را در نظر بگیرید که اولی به همراه Name است و نمونهی مشتق شدهی از آن، خاصیت init-only سن را نیز به همراه دارد:
public record User { public string Name { get; init; } public User(string name) { Name = name; } } public record UserWithAge : User { public int Age { get; init; } public UserWithAge(string name, int age) : base(name) { Age = age; } }
var user1 = new User("User 1"); var user2 = new UserWithAge("User 1", 21); Console.WriteLine("user1.Equals(user2) -> {0}", user1.Equals(user2)); Console.WriteLine("user1 == user2 -> {0}", user1 == user2);
user1.Equals(user2) -> False user1 == user2 -> False
امکان تعریف ارثبری رکوردها به صورت زیر نیز وجود دارد و الزاما نیازی به روش تعریف کلاس مانند آنها، مانند مثال فوق نیست:
public abstract record Food(int Calories); public record Milk(int C, double FatPercentage) : Food(C);
رکوردها متد ToString را بازنویسی میکنند
در مثال قبلی اگر یک ToString را بر روی اشیاء تشکیل شده فراخوانی کنیم:
Console.WriteLine(user1.ToString()); Console.WriteLine(user2.ToString());
User { Name = User 1 } UserWithAge { Name = User 1, Age = 21 }
امکان استفادهی از Deconstruct در رکوردها
دو روش برای تعریف رکوردها وجود دارند؛ یکی شبیه به تعریف کلاسها است و دیگری تعریف یک سطری، که positional record نیز نامیده میشود:
public record Person(string Name, int Age);
public void Deconstruct(out string Name, out int Age) { Name = this.Name; Age = this.Age; }
var (name, age) = new Person("User 1", 21);
امکان استفادهی از نوعهای record در ASP.NET Core 5x
سیستم model binding در ASP.NET Core 5x، از نوعهای record نیز پشتیبانی میکند؛ یک مثال:
public record Person([Required] string Name, [Range(0, 150)] int Age); public class PersonController { public IActionResult Index() => View(); [HttpPost] public IActionResult Index(Person person) { // ... } }
پرسش و پاسخ
آیا نوعهای record به صورت value type معرفی میشوند؟
پاسخ: خیر. رکوردها در اصل reference type هستند؛ اما از لحاظ مقایسه، شبیه به value types عمل میکنند.
آیا میتوان در یک کلاس، خاصیتی از نوع رکورد را تعریف کرد؟
پاسخ: بله. از این لحاظ محدودیتی وجود ندارد.
آیا میتوان در رکوردها، از struct و یا کلاسها جهت تعریف خواص استفاده کرد؟
پاسخ: بله. از این لحاظ محدودیتی وجود ندارد.
آیا میتوان از واژهی کلیدی with با کلاسها و یا structها استفاده کرد؟
پاسخ: خیر. این واژهی کلیدی در C# 9.0 مختص به رکوردها است.
آیا رکوردها به صورت پیشفرض Immutable هستند؟
پاسخ: اگر آنها را به صورت positional records تعریف کنید، بله. چون در این حالت خواص تشکیل شدهی توسط آنها از نوع init-only هستند. در غیراینصورت، میتوان خواص غیر init-only را نیز به تعریف رکوردها اضافه کرد.
کامپوننت jumbotron
از Jumbotron برای نمایش متنی مشخص در بالای یک صفحه، استفاده میشود. دو روش استفادهی از آن در بوت استرپ 4 وجود دارند:
- داخل container:
<div class="container"> <header class="jumbotron mt-4"> <div class="display-2 mb-4">Our Mission</div> <p class="lead">Wisdom Pet Medicine strives to blend the best in traditional and alternative medicine in the diagnosis and treatment of companion animals including dogs, cats, birds, reptiles, rodents, and fish. We apply the wisdom garnered in the centuries old tradition of veterinary medicine, to find the safest treatments and cures.</p> </header>
در اینجا با اعمال کلاس jumbotron، متن header، داخل یک قاب با گوشههای گرد قرار میگیرد و مشخصتر نمایش داده خواهد شد. همچنین با mt-4، فاصلهای را بین آن و بالای صفحه ایجاد کردهایم.
- خارج از container:
<header class="jumbotron jumbotron-fluid"> <div class="container"> <div class="display-2 mb-4">Our Mission</div> <p class="lead">Wisdom Pet Medicine strives to blend the best in traditional and alternative medicine in the diagnosis and treatment of companion animals including dogs, cats, birds, reptiles, rodents, and fish. We apply the wisdom garnered in the centuries old tradition of veterinary medicine, to find the safest treatments and cures.</p> </div> </header>
اگر میخواهیم این قاب، تمام عرض صفحه را پر کند و همچمنین لبههای گرد آن نیز حذف شوند، میتوان از کلاس jumbotron-fluid استفاده کرد و آنرا خارج از container قرار داد. سپس برای اینکه متن داخل آن با container زیر آن تراز شود، میتوان یک container را در اینجا داخل jumbotron تعریف کرد.
کنترل ظاهر جداول، در بوت استرپ 4
بوت استرپ 4 به همراه تعدادی کلاس ویژه است که برای بهبود ظاهر المان استاندارد جدول، ارائه شدهاند. آنها را در طی مثالهایی بررسی خواهیم کرد.
برای رسیدن به چنین تصویری، تغییرات زیر را بر روی یک جدول استاندارد HTML اعمال کردهایم:
<table class="table table-striped table-hover table-bordered table-responsive"> <thead class="thead-light">
- کلاس table-striped سبب میشود تا ردیفها، یک در میان با رنگی متمایز نمایش داده شوند.
- با افزودن table-hover، رنگ ردیفهای جدول با عبور اشارهگر ماوس از روی آنها تغییر میکند.
- کلاس table-bordered کار نمایش قاب جدول را انجام میدهد.
- کلاس table-responsive سبب میشود تا در اندازههای کوچک صفحه، یک اسکرول بار افقی برای نمایش آیتمهای جدول ظاهر شود و یا میتوان از کلاس table-sm نیز استفاده کرد تا padding تعریف شدهی در جدول، کاهش یابند. این کلاس، قابلیت پذیرش break-pointها را نیز دارد؛ مانند table-responsive-md.
- کلاسهای thead-light و یا thead-dark که بر روی تگ thead قرار میگیرند، رنگ پس زمینهی هدر جدول را مشخص میکنند.
- برای تغییر رنگ پس زمینه و متن یک ردیف میتوان از کلاسهای bg-color و text-color استفاده کرد:
<tr class="bg-danger text-light">
<td class="table-success">$100.00 </td>
کامپوننت جدید card در بوت استرپ 4
پنلهای بوت استرپ 3 حذف و بجای آن کامپوننت جدیدی به نام card در نگارش 4 آن ارائه شدهاست که با افزودن کلاس آن به یک div، بلافاصله قابی با گوشههای گرد به آن اضافه میشود.
<section class="card mb-5" id="drwinthrop"> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Winthrop Photo"> <h2 class="card-title">Dr. Stanley Winthrop</h2> <h5 class="card-subtitle">Behaviorist</h5> <p class="card-text">Dr. Winthrop is the guardian of Missy, a three-year old Llaso mix, who he adopted at the shelter. Dr. Winthrop is passionate about spay and neuter and pet adoption, and works tireless hours outside the clinic, performing free spay and neuter surgeries for the shelter.</p> <a class="card-link" href="#">About Me</a> <a class="card-link" href="#">My Pets</a> <a class="card-link" href="#">Client Slideshow</a> </div> </section>
- سپس یک card میتواند دارای تصویری واکنشگرا باشد که عرض card را پوشش میدهد. این تصویر با کلاس card-img مشخص میشود.
در اینجا امکان تعریف card-img-top و card-img-bottom نیز وجود دارند. این موارد تصویر card را در بالا و یا پایین آن، بدون padding، نمایش میدهند. اگر میخواهید متنی را بر روی این تصویر نمایش دهید، از کلاس card-img-overlay استفاده کنید. در این حالتها باید تصویر را خارج از card-body قرار دهید.
- عنوان و زیرعنوان یک card، توسط کلاسهای card-title و card-subtitle تعیین میشوند.
- متن داخل آنرا با کلاس card-text مشخص میکنیم.
- لینکهای ذیل آن نیز توسط کلاس card-link در طی یک ردیف نمایش داده میشوند.
امکان تعیین رنگ پس زمینه، حاشیه و متن یک card نیز وجود دارند:
<section class="card mb-5 bg-primary text-light border-warning" id="drchase">
و فرمول کلی رنگهای آن نیز به صورت زیر میباشد:
میتوان برای یک card، هدر و فوتر نیز تعریف کرد:
<section class="card mb-5" id="drsanders"> <div class="card-header"> <h2 class="card-title">Dr. Kenneth Sanders</h2> <h5 class="card-subtitle">Nutritionist</h5> </div> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Sanders Photo"> <p class="card-text">Leroy walked into Dr. Sanders front door when she was moving into a new house. After searching for weeks for Leroy's guardians, she decided to make Leroy a part of her pet family, and now has three cats.</p> </div> <div class="card-footer"> <a class="card-link" href="#">About Me</a> <a class="card-link" href="#">My Pets</a> <a class="card-link" href="#">Client Slideshow</a> </div> </section>
برای تعریف یک list-group در داخل یک card، به صورت زیر عمل میکنیم:
<section class="card mb-5" id="drwong"> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Wong Photo"> <h2 class="card-title">Dr. Olivia Wong</h2> <h5 class="card-subtitle">Preventive Care</h5> <p class="card-text">Dr. Wong is a cancer survivor who was fortunate enough to get to spend time with a therapy dog during her recovery. She became passionate about therapy animals, and has started her own foundation to train and provide education to patients in recovery. Now she gets her own dose of daily therapy from her husky, Lilla.</p> </div> <div class="list-group list-group-flush"> <a class="list-group-item" href="#">About Me</a> <a class="list-group-item" href="#">My Pets</a> <a class="list-group-item" href="#"> Client Slideshow </a> </div> </section>
تعیین نحوهی چیدمان cards در بوت استرپ 4
اگر چندین card در یک صفحه تعریف شدهاند، برای تعیین نحوهی قرارگیری آنها در کنار یکدیگر میتوان یا از سیستم طرحبندی متداول بوت استرپ استفاده کرده و یا امکان تعریف گروهی از آنها نیز وجود دارد. برای اینکار کافی است یک div با کلاس card-group را تعریف و سپس تمام cards را داخل آن قرار دهیم:
<div class="container"> <div class="card-group">
اگر از کلاس card-columns استفاده کنیم، تمام cards را به صورت خودکار در ستونها و ردیفها، قرار میدهد که بعضی از آنها بلندتر و بعضی دیگر کوتاهتر هستند (نوعی نمایش کاشیکاری شدهاست):
ولی در کل اگر نیاز به کنترل بیشتری دارید، از همان روش متداول تعریف ردیفها و ستونهای سیستم طرحبندی بوت استرپ استفاده کنید.
المان media در بوت استرپ 4
برای نمایش متداول متن و تصویر که قرار است تصویر، در یک ستون و متن، در ستونی دیگر باشد، بوت استرپ 4 به همراه کلاس media است که بر اساس Flexbox بازنویسی شدهاست.
<body> <div class="container"> <section class="media mb-5" id="drwinthrop"> <img class="d-flex align-self-center img-fluid rounded mr-3" style="width:30%" src="images/testimonial-mcphersons.jpg" alt="Doctor Winthrop Photo"> <div class="media-body"> <h2>Dr. Stanley Winthrop</h2> <h5>Behaviorist</h5> <p>Dr. Winthrop is the guardian of Missy, a three-year old Llaso mix, who he adopted at the shelter. Dr. Winthrop is passionate about spay and neuter and pet adoption, and works tireless hours outside the clinic, performing free spay and neuter surgeries for the shelter.</p> </section> </div> </body>
ابتدا توسط کلاس media یک container را تعریف میکنیم. سپس تصویر، یک ستون و media-body ستون دیگر را تشکیل میدهد.
با استفاده از d-flex، المان تصویر را به یک Flexbox container تبدیل کرده و با استفاده از کلاس align-self-center، آنرا در میانهی ستون قرار میدهیم. همچنین در اینجا توسط mr-3، فاصلهی آنرا با متن ستون کناری تنظیم کردهایم.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: Bootstrap4_09.zip
بررسی زبان Go برای توسعه دهندگان #C
A Tour of Go (golang) for the C# Developer
Learning other programming languages enhances our work in our primary language. From the perspective of a C# developer, the Go language (golang) has many interesting ideas. Go is opinionated on some things (such as where curly braces go and what items are capitalized). Declaring an unused variable causes a compile failure; the use of "blank identifiers" (or "discards" in C#) are common. Concurrency is baked right in to the language through goroutines and channels. Programming by exception is discouraged; it's actually called a "panic" in Go. Instead, errors are treated as states to be handled like any other data state. We'll explore these features (and others) by building an application that uses concurrent operations to get data from a service. These ideas make us think about the way we program and how we can improve our day-to-day work (in C# or elsewhere).
0:00 Welcome to Go
2:40 Step 1: Basics
12:20 Step 2: Calling a web service
23:35 Step 3: Parsing JSON
36:26 Step 4: "for" loops
41:00 Step 5: Interfaces and methods
50:05 Step 6: Time and Args
55:10 Step 7: Concurrency
1:07:10 Step 8: Errors
1:14:40 Step 9: Concurrency and errors
1:24:35 Where to go next