بهبود عملکرد و سرعت در کدنویسی
نسخه 10 سـی‌شارپ چه قابلیت‌هایی در اختیار برنـامــه‌نـویســان  قرارداده است؟
نسخه 10 زبان برنامه‌نویسی سی‌شارپ همراه با نسخه 6 چارچوب دات‌نت منتشر شد. در نسخه جدید قابلیت‌های کاربردی نسبتا مهمی در اختیار برنامه‌نویسان قرار گرفته و برخی قابلیت‌های قبلی بهبود پیدا کرده‌اند تا خوانایی این زبان محبوب بازهم بیشتر از قبل شود. در این مقاله نگاهی اجمالی به مهم‌ترین آن‌ها خواهیم داشت.

بررسی پارامتر تهی (Null Parameter Checking)

استثنا مرجع تهی (Null Reference Exception) یکی از خطاهای دردسرآفرین برنامه‌های کاربردی است. برنامه‌نویسان برای پیشگیری از بروز این خطا مجبور هستند ورودی‌های متدها را بررسی کنند، اما ویژگی جدید این فرآیند را ساده‌تر و خوانایی کدها را بیشتر کرده است. در حال حاضر برای بررسی تهی (خالی بودن) یک پارامتر از ترکیب نحوی زیر استفاده می‌شود:

public MyFunction(int id, SomeClass newObject)

}

if (newObject == null)

{

throw new ArgumentNullException(“newObject”);

}

// Code Here

{

در متد بالا، یک شیء به‌نام newObject از نوع SomeClass به پارامتر MyFunction تخصیص داده شده است. اگر شیء مذکور مقداردهی اولیه نشده باشد (تهی باشد) متد نباید کار کند. نسخه 10 سی‌شارپ این فرآیند ارزیابی را ساده کرده است. کافی است، دو کاراکتر !! به انتهای نام پارامتر اضافه کنید.

public MyFunction(int id, SomeClass newObject!!)

}

// Code Here

{

در قطعه کد بالا، به‌شکل خودکار تهی بودن newObject بررسی می‌شود و اگر نتیجه ارزیابی مثبت باشد، خطای ArgumentNullException تولید می‌شود که امکان مدیریت بدون مشکل آن وجود دارد. 

خاصیت‌های اجباری (Required Properties)

برنامه‌نویسان مجرب از سازنده‌ (Constructor) پیچیده در برنامه‌های خود استفاده نمی‌کنند و ترجیح می‌دهند از سازنده‌های ساده استفاده کنند. به‌بیان دیگر، ترجیح می‌دهند مقادیر را به‌شکل مستقیم به فیلدها ارجاع دهند. برنامه‌نویسان برای ساخت اشیاء از سازنده‌های سبک‌وزن همانند قطعه کد زیر استفاده می‌کنند: 

var Myconstructor = new MyClass

{

Title = “Hi Everyone”

Category = “.NET»,

ReleaseDate = DateTime.Now()

}

با این‌حال، گاهی‌اوقات باید خصلت‌ها مقداردهی اولیه شوند، اما ممکن است توسعه‌دهندگان این‌کار را فراموش کنند. در نسخه 10 سی‌شارپ کلمه کلیدی Required در ارتباط با خصلت‌ها معرفی شد. در این حالت هنگام ساخت کلاس، می‌توانیم یک فیلد اجباری تعریف کنیم که اگر هنگام نمونه‌سازی از کلاس، فیلد مذکور مقداردهی نشد، خطای زمان کامپایل ایجاد شود. 

public class MyClass

}

public required string Title {get; init;}

public string Category {get; init;}

public DateTime ReleaseDate {get; init;}

{

ویژگی Global Using

به‌طور معمول، برنامه‌نویسان در ابتدای سورس‌هایی که در سی‌شارپ می‌نویسند از دستور using استفاده می‌کنند که همراه با آن فضای‌نام (Namespace) قرار می‌گیرد. فضاهای نام پذیرای کلاس‌ها، متدها و اشیاء داده‌ای هستند که برنامه‌نویسان برای نوشتن کدهای خود به آن‌ها نیاز دارند. به‌طور مثال، System، System.Linq، System.Collections.Generic و غیره تقریبا در همه پروژه‌ها و فایل‌هایی که توسط زبان برنامه‌نویسی سی‌شارپ نوشته می‌شوند، وجود دارند. تیم توسعه دات‌نت و سی‌شارپ در نسخه 10 ویژگی Global Using را معرفی کرد. ویژگی فوق به برنامه‌نویسان اجازه می‌دهد برای وارد کردن (Import) یک فضای‌نام به‌جای آن‌که از دستور Using استفاده کنند از عبارت Global Using  استفاده کنند. تفاوت دستور جدید با دستور قبلی چیست؟ اگر در یکی از فایل‌های پروژه از Global Using استفاده کنید، نیازی نیست در فایل‌های دیگر پروژه، دومرتبه از همان Using استفاده کنید. به‌عبارت دقیق‌تر، دستور فوق قابلیت گسترش‌پذیری دارد و به دیگر فایل‌ها تعمیم داده می‌شود. 

برنامه‌نویسان می‌توانند از Global Using  در یکی از فایل‌های اصلی پروژه مثل فایل Program.cs استفاده کنند تا ویژگی فوق به فایل‌های دیگر تعمیم داده شود. اگر به‌دنبال برنامه‌نویسی ساخت‌یافته هستید، پیشنهاد می‌کنیم فایلی به‌نام GlobalNamespace.cs  در پروژه ایجاد کنید و تمام دستورات Using را در آن قرار دهید تا مجبور به تکرار دستورات نباشید. 

global using System;

global using System.Linq;

global using System.Collections.Generic;

برنامه‌نویسان می‌توانند به‌طور همزمان از Using و Global using در یک فایل استفاده کنند. همچنین، می‌توان از  Global Using برای وارد کردن کلاس‌های ایستا استفاده کرد. ترکیب نحوی این‌کار به‌شرح زیر است: 

global using static System.Console;

ویژگی  Implicit Using

پروژه‌هایی که با دات‌نت نسخه 6 توسعه داده می‌شوند، مجهز به قابلیتی هستند که Implicit Using نام دارد. توسعه‌دهندگان می‌توانند ویژگی فوق را فعال یا غیرفعال کنند. اگر قابلیت مذکور در پروژه‌ای فعال باشد، به‌شکل پیش‌فرض برخی Using‌ها را بر مبنای پروژه به آن اضافه می‌کند. به‌طور مثال، در ارتباط با برنامه‌های کنسول، Using‌های زیر به‌طور خودکار به تمامی فایل‌های پروژه اضافه می‌شوند. 

// <auto-generated/>

global using global::System;

global using global::System.Collections.Generic;

global using global::System.IO;

global using global::System.Linq;

global using global::System.Net.Http;

global using global::System.Threading;

global using global::System.Threading.Tasks;

همان‌گونه که مشاهده می‌کنید، ویژگی فوق کاملا کاربردی است. برنامه‌نویسان می‌توانند از روش‌های زیر برای فعال‌سازی ویژگی فوق استفاده کنند: 

اگر به بخش Properties پروژه در Solution Explorer در ویژوال استودیو بروید، گزینه‌ای به‌نام Implicit global using را مشاهده می‌کنید که امکان فعال یا غیرفعال کردن آن با فعال‌سازی تیک Using‌ها وجود دارد. 

دومین روش این است که فایل تنظیمات پروژه که فرمت فایلی .csproj نام دارد را باز کنید و مقدار برچسب  ImplicitUsings را فعال (Enbale) کنید. برای غیرفعال کردن قابلیت فوق، کافی است مقدار برچسب مذکور را Disable تنظیم کنید. 

<Project Sdk=”Microsoft.NET.Sdk”>

  <PropertyGroup>

    <OutputType>Exe</OutputType>

    <TargetFramework>net6.0</TargetFramework>

    <ImplicitUsings>enable</ImplicitUsings>

    <Nullable>enable</Nullable>

  </PropertyGroup>

</Project>

اگر دوست دارید تا بدانید چه Using‌هایی به‌طور خودکار به پروژه اضافه شده‌اند، پروژه را باز کنید و به مسیر Obj\Debug\Net6.0 بروید. در مسیر مذکور، فایلی به‌نام  GlobalUsings.g.cs  را مشاهده می‌کنید که  Usingها در آن قرار دارد. کامپایلر فایل مذکور را به‌طور خودکار برای پروژه‌هایی که روی دات‌نت 6 توسعه داده می‌شوند و قابلیت فوق در آن‌ها فعال شده است، ایجاد می‌کند. اگر در نظر دارید، گزینه‌های دیگری به Usingهای پیش‌فرض اضافه کنید، باید برچسب زیر را به برچسب‌های تنظیمات که .csproj نام دارد اضافه کنید. 

  <ItemGroup>

    <Using Include=”System.Numerics” />

  </ItemGroup>

در قطعه کد بالا فضای‌نام Numerics به موارد پیش‌فرض اضافه می‌شود. 

رشته‌های درون‌یابی ثابت

(Constant interpolated strings)

ویژگی مذکور، اجازه می‌دهد متغیرها و عبارت‌های محاسباتی را به روشی شفاف‌تر و خواناتر به رشته‌ها الحاق کرد. به‌طور سنتی، برنامه‌نویسان از عملگر مثبت (+) یا متد Format کلاس String برای الحاق رشته‌ها استفاده می‌کنند. به‌طور مثال، اگر در نظر داشته باشیم رشته جدید از طریق الحاق دو متغیر  firstName و lastName ایجاد کنیم، باید کاری مشابه حالت زیر انجام دهیم: 

var FirstName = “HamidReza”;

var LastName = “Taebi”;

var Firstattach = FirstName + “ “ + LastName;

var Secondattach = string.Format(“{0} {1}”, FirstName, LastName);

با ویژگی جدید  Interpolated Strings کاراکتر $ را قبل از رشته جدید قرار می‌دهیم و داخل کروشه نام متغیر یا عملیات محاسباتی را درج می‌کنیم. 

var OldMethod = $”{FirstName} {LastName}”;

همان‌گونه که مشاهده می‌کنید، ویژگی Interpolated Strings قالب‌بندی رشته‌ها و خوانایی کدها را بهتر کرده و اجازه می‌دهد با کدنویسی کمتری فرآیند الحاق را انجام دهید. با‌ این‌حال، ویژگی فوق یک به‌روزرسانی مهم دریافت کرده است. تا قبل از انتشار سی‌شارپ 10، برنامه‌نویسان نمی‌توانستند از ویژگی Interpolated Strings استفاده کنند و مقدار بازگشتی را درون ثابت‌های رشته‌ای قرار دهند و خروجی باید در یک متغیر درج می‌شد. از این پس، برنامه‌نویسان می‌توانند مقدار بازگشتی  Interpolated Strings را در یک ثابت رشته‌ای قرار دهند. ‌ویژگی مذکور Constant Interpolated Strings  نام دارد. 

private const string Myfirstname = “HamidReza”;

private const string Mylastname = “Taebi”;

private const string NewMethod = $”{ Myfirstname } { Mylastname }”;

دقت کنید تنها ثابت‌هایی از نوع رشته از طریق روش فوق قابل الحاق به‌ یک‌دیگر هستند و قرار دادن مقدار بازگشتی در یک ثابت رشته‌ای را امکان‌پذیر می‌کنند. از‌این‌رو، اگر تلاش کنید از تکنیک مذکور در ارتباط با نوع‌های دیگر استفاده کنید با پیغام خطا روبرو می‌شوید. 

تغییرات Lambda Expression در سی‌شارپ 10

یکی از کلمات کلیدی قدرتمند زبان برنامه‌نویسی سی‌شارپ، کلمه کلیدی var است. var به کامپایلر اجازه می‌دهد از روی مقادیر تخصیص داده شده به یک متغیر، نوع متغیر را تشخیص دهد و ضرورتی ندارد به‌شکل صریح نوع متغیر را تعریف کنیم. تا قبل از انتشار نسخه 10، کامپایلر سی‌شارپ اگر با قطعه کدی شبیه به var MyDelegate = () => Console.WriteLine(“Hello”); روبرو می‌شد، به‌دلیل این‌که توانایی تشخیص نوع Delegate را نداشت، پیغام خطا می‌داد. برنامه‌نویسان برای حل این مشکل مجبور بودند، نوع Delegate را مشخص کنند. 

Action MyDelegate = () => Console.WriteLine(“Hello”);

در نسخه 10 ویژگی Inferred Delegate Type افزوده شده تا کامپایلر بتواند نوع Delegate را تشخیص دهد. دقت کنید عبارت سمت راست که Lambda Expression  نام دارد باید برای کامپایر قابل فهم باشد. به‌طور مثال، فرض کنید قصد استفاده از کلمه کلیدی var را دارید و از ترکیب نحوی مثل var multiple = x => x * x; استفاده می‌کنید. کامپایلر نمی‌تواند نوع x را تشخیص دهد، بنابراین پیغام خطایی تولید می‌کند. برای آن‌که مشکل دستور فوق را برطرف کنیم، باید نوع x را دقیقا اعلام کنیم.

var multiple = (int x) => x * x;

موضوع مهم دیگری که باید به آن دقت کنید نوع خروجی Delegate است. اگر در نظر دارید Delegate بنویسید که دو نوع متفاوت را بازگرداند، کامپایلر نمی‌تواند نوع خروجی را تشخیص دهد و پیغام خطایی نشان می‌دهد. به‌طور مثال، دستور زیر را در نظر بگیرید

var result = (int x) => x > 10 ? 40 : “forty”;

در دستور بالا، نوع خروجی بر مبنای مقدار x، از نوع صحیح یا رشته‌ای است. کامپایلر نمی‌تواند نوع خروجی را تشخیص دهد و پیغام خطایی نشان می‌دهد. در نسخه جدید، برنامه‌نویسان توانایی تعیین نوع خروجی Lambda Expression را دارند. برای این‌کار، قبل از ورودی‌های عبارت لامبدا، نوعی را تعیین می‌کنند که نوع خروجی عبارت لامبدا را مشخص می‌کند. حال اگر دستور بالا را به‌شکل زیر بنویسیم مشکلی ایجاد نمی‌شود:

var result = object (int x) => x > 10 ? 40 : “forty”;

در دستور بالا، مشخص کردیم که نوع خروجی عبارت لامبدا از نوع Object است. نوع Object نشان می‌دهد که خروجی می‌تواند هر نوعی داشته باشد. در این حالت، دست کامپایلر برای تشخیص نوع خروجی Delegate باز است. به ویژگی مذکور «نوع بازگشتی لامبدا» (Lambda Return Type) گفته می‌شود.

تعریف خصلت روی عبارت لامبدا، ويژگی دیگر افزوده شده به عبارت‌های لامبدا است. مانند متدهای عادی می‌توان به عبارت‌های لامبدا خصلت اضافه کرد که ویژگی مذکور «خصلت لامبدا» (Lambda Expression) نام دارد. به‌طور مثال، فرض کنید در نظر داریم Attribute Obsolete  را به عبارت لامبدا اضافه کنیم. ترکیب نحوی انجام این‌کار به‌صورت زیر است: 

var result = [Obsolete] object (int x) => x > 10 ? 40 : “forty”;

اضافه شدن دو نوع جدید DateOnly و  TimeOnly

DateTime از نوع‌های قدیمی دنیای برنامه‌نویسی است که قدیمی‌ها کاملا با آن آشنا هستند. همان‌گونه که اطلاع دارید، نوع DateTime اطلاعات زمان و تاریخ را نگه‌داری می‌کند. به‌طور مثال، اگر دستور DateTime.Now را فراخوانی کنیم، تاریخ و زمان جاری را نشان می‌دهد. قبل از انتشار نسخه 10 سی‌شارپ، اگر تنها تاریخ یا زمان را نیاز داشتیم، باید به‌صراحت نوع موردنظر را انتخاب می‌کردیم. در نسخه 10 دو نوع جدید  DateOnly و TimeOnly اضافه شده تا تاریخ و زمان به شکل مجزا قابل استفاده باشند. ترکیب نحوی استفاده شده از نوع‌های جدید به‌صورت زیر است: 

DateOnly Justdate = DateOnly.FromDateTime(DateTime.Now);

TimeOnly Justtime = TimeOnly.FromDateTime(DateTime.Now);

Console.WriteLine(Justdate);

Console.WriteLine(Justtime);

همان‌گونه که مشاهده می‌کنید، مقادیر تاریخ و زمان در دو شیء جدا نگه‌داری می‌شوند. در این‌جا Justdate تنها تاریخ را نگه‌داری می‌کند و  Justtime تنها زمان را نگه‌داری می‌کند. بزرگ‌ترین مزیتی که افزودن این دو نوع جدید برای برنامه‌نویسان دارد، هماهنگی بیشتر نوع‌های تاریخ و زمان در  SQL Server است، زیرا به‌لحاظ داده‌ای شباهت بیشتری به هم دارند. 

بهبود عملکرد struct 

ساختارها در نگارش 10 سی‌شارپ تغییراتی داشته‌اند. یکی از این تغییرات، تعریف سازنده بدون پارامتر در struct است. تا قبل از انتشار نسخه 10، امکان تعریف سازنده بدون پارامتر وجود نداشت و توسعه‌دهندگان مجبور بودند حداقل یک پارامتر برای یک struct  تعریف کنند. ویژگی مذکور «سازندگان ساختار بدون پارامتر» (Parameterless Struct Constructors) نام دارد. برای آشنایی بهتر با مفهوم فوق به قطعه کد زیر دقت کنید: 

struct Point

{

    public Point()

    {

        X = 0;

        Y = 0;

    }

    public double X { get; set; }

    public double Y { get; set; }

}

همان‌گونه که مشاهده می‌کنید، ساختار Point یک سازنده بدون پارامتر دارد. دقت کنید که درون سازنده باید تمام خاصیت‌های آن‌را مقداردهی کنید، در غیر این‌صورت با پیغام خطای زیر روبرو می‌شوید. در پیغام خطای زیر کامپایلر اعلام می‌دارد که Y مقداردهی اولیه نشده است. 

Auto-implemented property ‘Point.Y’ must be fully assigned before control is returned to the caller.

قابلیت دیگری که همراه با نگارش 10 به ساختارها افزوده شده، struct field initializers نام دارد. ویژگی فوق اجازه می‌دهد هنگام تعریف خاصیت، آن‌را مقداردهی کرد. توسعه‌دهندگان می‌توانند از ترکیب زیر برای این منظور استفاده کنند: 

public double X { get; set; } = 0;

راه‌حل فوق باعث می‌شود تا کامپایلر پیغام خطایی نشان ندهد، زیرا خاصیت‌های ساختار همگی مقداردهی اولیه شده‌اند. نکته ظریفی که هنگام استفاده از تکنیک فوق باید دقت کنید این است که انتهای دستور از سمی‌کالن (;) استفاده کنید.

قابلیت جالب دیگری که به ساختارها اضافه شده، With نام دارد. ویژگی مذکور اجازه می‌دهد یک کپی از شیء ساخته‌شده از ساختار تهیه کنید و در صورت نیاز برخی از خاصیت‌های آن‌ها را تغییر دهید. 

var p1 = new Point(12, 13);

var p2 = p1 with { Y = 49 };

در قطعه کد بالا، شی p1 با مقادیر 12 برای X و 13 برای Y تعریف شده است. در خط دوم از کلمه کلیدی  with برای ساخت یک کپی از p1  استفاده شده و در ادامه مقدار Y  به 49 تغییر پیدا کرده است. در این حالت، شیء p2 با مقدار جدید ساخته می‌شود. 

تغییرات مهم Property Pattern در نسخه 10 

برای اولین بار در نسخه ۸ زبان سی‌شارپ، قابلیت Property Pattern معرفی شد. توسعه‌دهندگان می‌توانستند از قابلیت فوق برای ارزیابی اشیاء با مقادیر خصلت‌های مرتبط استفاده کنند که نقش مهمی در خوانایی و درک ساده‌تر کدها داشت. به‌طور مثال، فرض کنید دو کلاس Person و Car دارید و در نظر دارید متدی بنویسید و این موضوع را بررسی کنید که آیا شخصی ماشین‌های قرمز دارد یا خیر. برای انجام این‌کار قطعه کدی مشابه زیر می‌نویسیم:

public class Person

{

    public string Name { get; set; }

    public Car? Car { get; set; }

}

public class Car

{

    public string Color { get; set; }

}

static bool HasPersonRedCar(Person person) => person is { Car: { Color : “Red”} };

در ادامه یک شیء از کلاس Person ایجاد می‌کنیم و متد HasPersonRedCar را روی شیء جدید فراخوانی می‌کنیم. 

var ali = new Person()

{

    Name = “Alex”,

    Car = new Car

    {

        Color = “Red”,

    }

};

Console.WriteLine(HasPersonRedCar(Alex));

قطعه کد فوق مقدار true را باز می‌گرداند. 

همان‌گونه که مشاهده می‌کنید، Car خاصیت شیء Person را بررسی می‌کند و اگر مقدار خاصیت Color  برابر با  Red باشد مقدار True را باز می‌گرداند، در غیر این‌صورت مقدار False باز گردانده می‌شود. در مدل فوق، برای بررسی مقدار هر خاصیت مجبور هستیم یک جفت آکولاد باز و بسته بنویسیم. در نگارش 10 سی‌شارپ این قابلیت بهبود پیدا کرد تا نحوه نوشتن کدها ساده‌تر و خوانایی آن‌ها بیشتر شود. بر مبنای اصطلاحات جدید، قطعه کد بالا را می‌توان به‌صورت زیر بازنویسی کرد: 

static bool HasPersonRedCar(Person person) => person is { Car.Color : “Red” }

همان‌گونه که مشاهده می‌کنید آکولادهای پیرامون خاصیت Color حذف شده و از عملگر نقطه استفاده شده است.

ماهنامه شبکه را از کجا تهیه کنیم؟
ماهنامه شبکه را می‌توانید از کتابخانه‌های عمومی سراسر کشور و نیز از دکه‌های روزنامه‌فروشی تهیه نمائید.

ثبت اشتراک نسخه کاغذی ماهنامه شبکه     
ثبت اشتراک نسخه آنلاین

 

کتاب الکترونیک +Network راهنمای شبکه‌ها

  • برای دانلود تنها کتاب کامل ترجمه فارسی +Network  اینجا  کلیک کنید.

کتاب الکترونیک دوره مقدماتی آموزش پایتون

  • اگر قصد یادگیری برنامه‌نویسی را دارید ولی هیچ پیش‌زمینه‌ای ندارید اینجا کلیک کنید.

ایسوس

نظر شما چیست؟