مهندسی معکوس سمت سرور WhatsApp
Primary Constructors چیست؟
Primary Constructors، قابلیتی است که به C# 12 اضافه شدهاست تا توسط آن بتوان خواص را مستقیما توسط پارامترهای سازندهی یک کلاس تعریف و همچنین مقدار دهی کرد. هدف از آن، کاهش قابل ملاحظهی یکسری کدهای تکراری و مشخص است تا به کلاسهایی زیباتر، کمحجمتر و خواناتر برسیم. برای مثال کلاس متداول زیر را درنظر بگیرید:
public class Employee { public string FirstName { get; set; } public string LastName { get; set; } public DateTime HireDate { get; set; } public decimal Salary { get; set; } public Employee(string firstName, string lastName, DateTime hireDate, decimal salary) { FirstName = firstName; LastName = lastName; HireDate = hireDate; Salary = salary; } }
اکنون اگر بخواهیم همین کلاس را با استفاده از ویژگی Primary Constructor اضافه شده به C# 12.0 بازنویسی کنیم، به قطعه کد زیر میرسیم:
public class Employee(string firstName, string lastName, DateTime hireDate, decimal salary) { public string FirstName { get; set; } = firstName; public string LastName { get; set; } = lastName; public DateTime HireDate { get; set; } = hireDate; public decimal Salary { get; set; } = salary; }
var employee = new Employee("John", "Doe", new DateTime(2020, 1, 1), 50000);
یک نکته: اگر از Rider و یا ReSharper استفاده میکنید، یک چنین Refactoring توکاری جهت سهولت کار، به آنها اضافه شدهاست و به سرعت میتوان این تبدیلات را توسط آنها انجام داد.
توضیحات:
- متد سازنده در این حالت، به ظاهر حذف شده و به قسمت تعریف کلاس منتقل شدهاست.
- تمام مقدار دهیهای آغازین موجود در متد سازندهی پیشین نیز حذف شدهاند و مستقیما به قسمت تعریف خواص، منتقل شدهاند.
در نتیجه از یک کلاس 15 سطری، به کلاسی 7 سطری رسیدهایم که کاهش حجم قابل ملاحظهای را پیدا کردهاست.
نکته 1: هیچ ضرورتی وجود ندارد که به همراه یک primary constructor، خواصی هم مانند مثال فوق ارائه شوند؛ چون پارامترهای آن در تمام اعضای این کلاس، به همین شکل، قابل دسترسی هستند. در این مثال صرفا جهت بازسازی کد قبلی، این خواص اضافی را مشاهده میکنید. یعنی اگر تنها قرار بود، کار تزریق وابستگیها صورت گیرد که عموما به همراه تعریف فیلدهایی جهت انتساب پارامترهای متد سازنده به آنها است، استفاده از یک primary constructor، کدهای فوق را بیش از این هم فشردهتر میکرد و ... یک سطری میشد.
نکته 2: استفاده از پارامترهای سازندهی اولیه، صرفا جهت مقدار دهی خواص عمومی یک کلاس، یک code smell هستند! چون میتوان یک چنین کارهایی را به نحو شکیلتری توسط required properties معرفی شدهی در C# 11، پیاده سازی کرد.
بررسی تاریخچهی primary constructors
همانطور که در مقدمهی بحث نیز عنوان شد، primary constructors قابلیت جدیدی نیست و برای نمونه به همراه C# 9 و مفهوم جدید رکوردهای آن، ارائه شد:
public record class Book(string Title, string Publisher);
پس از آن در C# 10، این توسعه ادامه یافت و به امکان تعریف record structها، بسط یافت که در اینجا هم قابلیت تعریف primary constructors وجود دارد:
public record struct Color(int R, int G, int B);
پس از این مقدمات، اکنون در C# 12 نیز میتوان primary constructors را به تمام کلاسها و structهای معمولی هم اعمال کرد؛ با این تفاوت که در اینجا برخلاف رکوردها، کدهای خواصهای متناظر، به صورت خودکار تولید نمیشوند و اگر به آنها نیاز دارید، باید آنها را همانند مثال ابتدای بحث، خودتان به صورت دستی تعریف کنید.
primary constructors کلاسها و structهای معمولی، با primary constructors رکوردها یکی نیست
در C# 12 و به همراه معرفی primary constructors مخصوص کلاسها و structهای معمولی آن، از روش متفاوتی برای دسترسی به پارامترهای تعریف شده، استفاده میکند که به آن capturing semantics هم میگویند. در این حالت پارامترهای تعریف شدهی در یک primary constructor، توسط هر عضوی از آن کلاس قابل استفادهاست که یکی از کاربردهای آن، ساده کردن تعاریف تزریق وابستگیها است. در این حالت دیگر نیازی نیست تا ابتدا یک فیلد را برای انتساب به پارامتر تزریق شده تعریف کرد و سپس از آن فیلد، استفاده نمود؛ مستقیما میتوان با همان پارامتر تعریف شده، در متدها و اعضای کلاس، کار کرد.
برای مثال سرویس زیر را که از تزریق وابستگیها، در سازندهی خود استفاده میکند، درنظر بگیرید:
public class MyService { private readonly IDepedent _dependent; public MyService(IDependent dependent) { _dependent = dependent; } public void Do() { _dependent.DoWork(); } }
public class MyService(IDependent dependent) { public void Do() { dependent.DoWork(); } }
البته مفهوم Captures هم در زبان #C جدید نیست و در ابتدا به همراه anonymous methods و بعدها به همراه lambda expressions، معرفی و بکار گرفته شد. برای مثال درون یک lambda expression، اگر از متغیری خارج از آن lambda expressions استفاده شود، کامپایلر یک capture از آن متغیر را تهیه کرده و استفاده میکند.
بنابراین به صورت خلاصه primary constructors در رکوردها، با هدف تعریف خواص عمومی فقط خواندنی، ارائه شدند؛ اما primary constructors ارائه شدهی در C# 12 که اینبار قابل اعمال به کلاسها و structs معمولی است، بیشتر هدف ساده سازی تعریف کدهای تکراری private fields را دنبال میکند. برای نمونه این کدی است که کامپایلر برای primary constructor مثال ابتدای بحث تولید میکند و در اینجا نحوهی تولید خودکار این فیلدهای خصوصی را مشاهده میکنید:
using System; using System.Diagnostics; using System.Runtime.CompilerServices; namespace CS8Tests { [NullableContext(1)] [Nullable(0)] public class Employee { [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string <FirstName>k__BackingField; [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string <LastName>k__BackingField; [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private DateTime <HireDate>k__BackingField; [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private Decimal <Salary>k__BackingField; public Employee(string firstName, string lastName, DateTime hireDate, Decimal salary) { this.<FirstName>k__BackingField = firstName; this.<LastName>k__BackingField = lastName; this.<HireDate>k__BackingField = hireDate; this.<Salary>k__BackingField = salary; base..ctor(); } public string FirstName { [CompilerGenerated] get { return this.<FirstName>k__BackingField; } [CompilerGenerated] set { this.<FirstName>k__BackingField = value; } } public string LastName { [CompilerGenerated] get { return this.<LastName>k__BackingField; } [CompilerGenerated] set { this.<LastName>k__BackingField = value; } } public DateTime HireDate { [CompilerGenerated] get { return this.<HireDate>k__BackingField; } [CompilerGenerated] set { this.<HireDate>k__BackingField = value; } } public Decimal Salary { [CompilerGenerated] get { return this.<Salary>k__BackingField; } [CompilerGenerated] set { this.<Salary>k__BackingField = value; } } } }
یک نکته: برای مشاهدهی یک چنین کدهایی میتوانید از منوی Tools->IL Viewer برنامهی Rider استفاده کرده و در برگهی ظاهر شده، گزینهی #Low-Level C آنرا انتخاب نمائید.
امکان تعریف سازندههای دیگر، به همراه سازندهی اولیه
اگر به کدهای #Low-Level C تولیدی فوق دقت کنید، این کلاس، به همراه یک سازندهی خالی بدون پارامتر (parameter less constructor) نیست و سازندهی پیشفرضی (default constructor) برای آن درنظر گرفته نشدهاست ... اما اگر کلاسی به همراه یک primary constructor تعریف شد، میتوان با استفاده از واژهی کلیدی this، سازندهی ثانویهای را هم برای آن تعریف کرد:
public class Person(string firstName, string lastName) { public Person() : this("John", "Smith") { } public Person(string firstName) : this(firstName, "Smith") { } public string FullName => $"{firstName} {lastName}"; }
امکان ارثبری و تعریف سازندهی اولیه
مثال زیر را درنظر بگیرید که در آن کلاس مشتق شدهی از کلاس User، یک سازندهی اولیه را تعریف کرده:
public class User { public User(string firstName, string lastName) { } } public class Editor(string firstName, string lastName) : User { }
البته این محدودیت با structها وجود ندارد؛ چون structها، value type هستند و همواره به صورت پیشفرض، به همراه یک سازندهی پیش فرض بدون پارامتر، تولید میشوند.
یک مثال: قطعه کد متداول ارثبری زیر را درنظر بگیرید که در آن، کلاس مشتق شده به کمک واژهی کلید base، امکان تعریف سازندهی جدیدی را یافته و یکی از پارامترهای سازندهی کلاس پایه را مقدار دهی میکند:
public class Automobile { public Automobile(int wheels, int seats) { Wheels = wheels; Seats = seats; } public int Wheels { get; } public int Seats { get; } } public class Car : Automobile { public Car(int seats) : base(4, seats) { } }
public class Automobile(int wheels, int seats) { public int Wheels { get; } = wheels; public int Seats { get; } = seats; } public class Car(int seats) : Automobile(4, seats);
و یا یک نمونه مثال دیگر آن به صورت زیر است که در آن، ذکر بدنهی کلاس در C# 12، الزامی ندارد:
public class MyBaseClass(string s); // no body required public class Derived(int i, string s, bool b) : MyBaseClass(s) { public int I { get; set; } = i; public string B => b.ToString(); }
توصیه به پرهیز از double capturing
با مفهوم capture در این مطلب آشنا شدیم. در مثال زیر دوبار از پارامتر سازندهی age، در دو قسمت عمومی شده، استفاده شدهاست:
public class Human(int age) { // initialization public int Age { get; set; } = age; // capture public string Bio => $"My age is {age}!"; }
var p = new Human(42); Console.WriteLine(p.Age); // Output: 42 Console.WriteLine(p.Bio); // Output: My age is 42! p.Age++; Console.WriteLine(p.Age); // Output: 43 Console.WriteLine(p.Bio); // Output: My age is 42! // !
درک بهتر آن، نیاز به #Low-Level C کلاس Human را دارد:
using System.Diagnostics; using System.Runtime.CompilerServices; namespace CS8Tests { [NullableContext(1)] [Nullable(0)] public class Human { [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int <age>P; [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int <Age>k__BackingField; public Human(int age) { this.<age>P = age; this.<Age>k__BackingField = this.<age>P; base..ctor(); } public int Age { [CompilerGenerated] get { return this.<Age>k__BackingField; } [CompilerGenerated] set { this.<Age>k__BackingField = value; } } public string Bio { get { DefaultInterpolatedStringHandler interpolatedStringHandler = new DefaultInterpolatedStringHandler(11, 1); interpolatedStringHandler.AppendLiteral("My age is "); interpolatedStringHandler.AppendFormatted<int>(this.<age>P); interpolatedStringHandler.AppendLiteral("!"); return interpolatedStringHandler.ToStringAndClear(); } } } }
public Human(int age) { this.<age>P = age; this.<Age>k__BackingField = this.<age>P; base..ctor(); }
طبقه بندی Bad Code Smell ها
انتقال WebAssembly به سرور یا WASI
Bringing WebAssembly to the .NET Mainstream - Steve Sanderson, Microsoft
Many developers still consider WebAssembly to be a leading-edge, niche technology tied to low-level systems programming languages. However, C# and .NET (open-source, cross-platform technologies used by nearly one-third of all professional developers [1]) have run on WebAssembly since 2017. Blazor WebAssembly brought .NET into the browser on open standards, and is now one of the fastest-growing parts of .NET across enterprises, startups, and hobbyists. Next, with WASI we could let you run .NET in even more places, introducing cloud-native tools and techniques to a wider segment of the global developer community. This is a technical talk showing how we bring .NET to WebAssembly. Steve will demonstrate how it runs both interpreted and AOT-compiled, how an IDE debugger can attach, performance tradeoffs, and how a move from Emscripten to WASI SDK lets it run in Wasmtime/Wasmer or higher-level runtimes like wasmCloud. Secondly, you'll hear lessons learned from Blazor as an open-source project - challenges and misconceptions faced bringing WebAssembly beyond early adopters. [1] StackOverflow survey 2021
درضمن باید تنظیمات زیر روا هم اعمال کنید
Everywhere the problem to this solution was mentioned as re-registering aspNet by using aspnet_regiis.exe. But this did not work for me. Though this is a valid solution (as explained beautifully here) but it did not work with Windows 8. For Windows 8 you need to Windows features and enable everything under ".Net Framework 3.5" and ".Net Framework 4.5 Advanced Services".
بنده نیاز به یک تابع جاوا اسکریپتی ترجیحاً با Jquery دارم که بتونه تاریخ شمسی مثلا 1392/01/11 را بگیره و بگه که تا امروز چند سال و چند ماه گذشته. یعنی یک جور محاسبه سایقه کار برحسب سال و ماه را میخواهم روز و ساعتش مهم نیست. با تشکر
Entity Framework 7 (EF7) Preview 5 has shipped with support for Table-per-Concrete type (TPC) mapping. This blog post will focus on TPC. There are several other enhancements included in Preview 5, such as:
- Support for AT TIME ZONE in SQL Server
- Updates to command and connection interception (#23087, #23085, #17261)
- Addition of the delete behavior attribute
Read the full list of EF7 Preview 5 enhancements.
PdfRpt-2.2.zip
- Improved speed of the StronglyTypedListDataSource & AnonymousTypeListDataSource, using fast Reflection.Emit techniques. - Added iTextSharp's XmlWorker support (both LTR and RTL are supported). - Added XHtmlField, XHtmlFooterProvider & XHtmlHeaderProvider classes (using new XmlWorker). These new classes are replacements of old HtmlField, HtmlFooterProvider & HtmlHeaderProvider classes (using depreciated HTMLWorker).