ویژگی های جدید در C# 7

دوشنبه 25 مرداد 1395

در این مقاله قصد داریم چند ویژگی از ویژگی های جدید و مفید 7#C مانند Record type ، Tuple ، Pattern Matching را همراه با مثال توضیح دهیم.

ویژگی های جدید در C# 7

تاپل(Tuple) چیست؟

تاپل ها برای  گروهبندی موقت مقادیر مورد استفاده قرار میگیرند . شما می توانید یک تاپل را با یک کلاس POCO مقایسه کنید ، و به جای تعریف آن به عنوان یک کلاس،  می توانید آن را درfly تعریف کنید. در زیر یک مثال از چنین کلاسی است:

class PropertyBag
{
    public int Id {get; set;}
    public string Name {get; set;}
}
var myObj = new PropertyBag { Id = 1, Name = "test};

در مثال بالا در واقع نیازی به نام گذاری نبود.در کار شاید برای ساختارهای موقتی نیازی به نام گذاری نداشته باشیم. 

Tuples ها راهی برای ساختن ساختارهای موقتی روی fly هستند که نیازی به ساختن کلاس ها ندارند.

چرا؟

رایج ترین دلیل برای داشتن یک گروه از مقادیری که به صورت موقت گروه بندی می شوند ، مقادیر بازگشتی متعدد از یک متد است. در حال حاضر، چند راه برای انجام این کار در C # وجود دارد:

پارامترهای خروجی (Out parameters)

public void GetLatLng(string address, out double lat, out double lng) { ... }
 
double lat, lng;
GetLatLng(myValues, out lat, out lng);
Console.WriteLine($"Lat: {lat}, Long: {lng}"); 

استفاده از out-parameters (پارامتر خروجی) چندین مشکل دارد:

•  نمیتواند از این برای async-methods استفاده شود.

مجبور به اعلام پارامترهای  upfront است (باید نوع  مشخص شود ، نمیتوان از Var استفاده کرد )

نوع تاپل (Tuple-type)

در حال حاظر در #C چند Tuple-type وجود دارد که مانند native tuple عمل میکنند.

شما میتوانید متد قبل را به صورت زیر بازنویسی کنید:

public Tuple<int, int> GetLatLng(string address) { ... }
 
var latLng = GetLatLng("some address");
Console.WriteLine($"Lat: {latLng.Item1}, Long: {latLng.Item2}"); 

این  نوع ،معایب پارامتر خروجی را ندارد، اما نتیجه کد و  نتیجه تاپل  برای  پروپرتی با نام هایی شبیه به ITEM1 و ITEM2 مبهم است .

کلاس / ساختار (Class / struct)

شما همچنین میتوانید یک نوع جدید تعریف کنید و از آن به صورت نوع بازگشتی استفاده کنید.

struct LatLng{ public double Lat; public double Lng;}
public LatLng GetLatLng(string address) { ... }
 
var ll= GetLatLng("some address");
Console.WriteLine($"Lat: {ll.Lat}, Long: {ll.Lng}"); 

این مورد هیچ یک از معایب پارامتر خروجی و نوع تاپل را ندارد ، اما  نسبتا طولانی و در overhead بی معنی است.

چگونه؟

چند مورد  مختلف برای تاپل ، که توسط C# 7 Tuple استفاده میشود ، وجود دارد.

نوع بازگشتی تاپل(Tuple return types):

شما می توانید نوع بازگشتی متعدد برای یک تابع  مشخص کنید ، در اکثر مواقع برای مشخص کردن نوع ورودی های متعدد ، Syntax مشابه است . (method arguments)

public (double lat, double lng) GetLatLng(string address) { ... }
 
var ll = GetLatLng("some address"); 
Console.WriteLine($"Lat: {ll.lat}, Long: {ll.lng}");

تاپل های درون خطی (Inline tuples):

شما همچنین می توانید تاپل های درون خطی ایجاد کنید:

var ll = new (double lat, double lng) { lat = 0, lng = 0 };

ساختار زدایی تاپل (Tuple deconstruction):

ممکن است که شما نخواهید به همه ی بسته های نرم افزاری دسترسی داشته باشید، و  مستقیما مقادیر داخلی را دریافت کنید.بجای دسترسی به پروپرتی های تاپل (به عنوان مثال  انواع تاپل بازگشتی) ، از تاپل destructure مستقیما استفاده کنید.

(var lat, var lng) = GetLatLng("some address");
Console.WriteLine($"Lat: {lat}, Long: {lng}");

انواع رکورد(Record types)

Record types ،مجموعه ای ساده از پروپرتی هاست ،و  یک نوع داده (data type) که فقط شامل پروپرتی ها است.

چرا؟

اغلب کلاسها  و یا struct ها ،صرفا مجموعه ای از پروپرتی ها هستند. آنها هنوز هم نیاز به اعلام(declare) کامل  که کاملا طولانی است ، دارند . کلاس زیر نشان می دهد که یک کلاس با 3 پروپرتی  نیاز به کمی متن(text) برای  اعلام دارد:

class MyPoint
{
    int _x;
    int _y;
    int _z;
    MyPoint(int x, int y, int z){
        this._x = x;
        this._y = y;
        this._z = z;
    }
    public int X {get{ return this._x;}}
    public int Y {get{ return this._y;}}
    public int Z {get{ return this._z;}}
}

چگونه؟

باتایپ رکورد شما می توانید کد بالا را در یک خط بنویسید:


class Point(int X, int Y, int Z);

چند مورد بیشتر در باره ی آن:
کلاس ،به طور خودکار < IEquatable<Point را اجرا میکند ، که به معنی این است که می توانید ،  بجای مقایسه مرجع دو رکورد types based   ، مقادیر آنها را مقایسه کنید
متد ToString -برای  خروجی مقادیر در رکورد است.

تطبیق الگو(Pattern Matching)

چیست؟
باتایپ رکورد در تعامل است . تطبیق الگو بدان معنی است که شما می توانید نوع داده را تغییر دهید ، و باید یک یا statement های دیگر را اجرا کنید.

چرا؟

با وجودی که تطبیق الگو بسیار شبیه if/else   است ،  دارای مزایای خاص نیز میباشد
شما می توانید تطبیق الگو را بر روی هر نوع داده انجام دهید، حتی در حالی که if/else  همیشه نیاز اولیه برای مطابقت داشته باشد.
تطبیق الگو می تواند مقادیری از expression خود را استخراج کند.

چگونه؟

به مثال زیر توجه کنید:

class Geometry();
class Triangle(int Width, int Height, int Base) : Geometry;
class Rectangle(int Width, int Height) : Geometry;
class Square(int width) : Geometry;
 
Geometry g = new Square(5);
switch (g)
{
    case Triangle(int Width, int Height, int Base):
        WriteLine($"{Width} {Height} {Base}");
        break;
    case Rectangle(int Width, int Height):
        WriteLine($"{Width} {Height}");
        break;
    case Square(int Width):
        WriteLine($"{Width}");
        break;
    default:
        WriteLine("<other>");
        break;
}

 Non-nullable reference types

چیست؟

مقادیر Nullable  در C# 2.0 معرفی شدند.این موارد به خصوص همراه با  کلاس های <Nullable<T مفید می باشند.

Non-nullable reference types  برعکس این ویژگی ها هستند. این ویژگی به شما اجازه می دهد تا نوع reference هایی را ایجاد کنید که به صورت قطعی، null نخواهند بود.

چرا؟

NullReference exceptions  بسیار رایج هستند.

دو مشکل وجود دارد: اول این که شما null بودن آن ها را چک نمی کنید و به همین خاطر ممکن است با runtime exceptions مواجه شوید.

اگر بخواهید این موارد را بررسی کنید، با مشکل دیگری روبرو می شوید. کد شما طولانی و خسته کننده می شود و از هدفی که قبلا داشته اید، دور می شوید.

توانایی تعریف یک  reference type در قالب  non-nullable بر این مشکلات غلبه میکند.

چگونه؟

نکته:این syntax هنوز در حال استفاده است و ممکن است تغییر کند..syntax های احتمالی دیگری نیز وجود دارند که هنوز فرم قطعی برای انها مشخص نشده است.

زمانی که ما از واژه error  استفاده می کنیم مشخص نیست که یک خطای کامپایلری است یا فقط یک warning.

اول از همه ، syntax مطلوب این است که reference types ها non-nullable باشند.

این یک تقارنی بین reference و value types را اماده میکند.

int a;     //non-nullable value type
int? b;    //nullable value type
string c;  //non-nullable reference type
string? d; //nullable reference type

هرچند،ملیون ها خط در در #C وجود دارد

------------------------------------------

int a;     //non-nullable value type
int? b;    //nullable value type
string! c; //non-nullable reference type
string d;  //nullable reference type

استفاده از nullable و non-nullable types  بر روی کامپایلر اثر میگذارد.

MyClass a;  // Nullable reference type
MyClass! b; // Non-nullable reference type
 
a = null;   // OK, this is nullable
b = null;   // Error, b is non-nullable
b = a;      // Error, n might be null, s can't be null
 
WriteLine(b.ToString()); // OK, can't be null
WriteLine(a.ToString()); // Warning! Could be null!
 
if (a != null) { WriteLine(a.ToString); } // OK, you checked
WriteLine(a!.Length); // Ok, if you say so

استفاده از این syntax ایرادی ندارد اما ممکن است که برای ساختمان های داده generic  مشکل ایجاد کند.

// The Dictionary is non-nullable but string, List and MyClass aren't

Dictionary<string, List<MyClass>>! myDict; // روشی مناسب برای declare کردن همه ی تایپ های non-nullable است.  Dictionary<string!, List<MyClass!>!>! myDict;

این کد بالا مقداری از نظر خوانایی سخت است.بنا براین shortcut  را اماده کرده ایم:

// Typing ! in front of the type arguments makes all types non-nullable
Dictionary!<string, List<MyClass>> myDict;

 توابع محلی C# 7

چیست؟

توانایی declare  کردن متد ها و تایپ ها در block scope.

چرا؟

این عمل  با استفاده از Func and Action types با anonymous methods انجام میشود.

• Generics

• ref and out parameters

• params

تابع های Local تماما مانند  normal methods هستند با این تفاوت که Local function ها در حوزه خودشان تعریف میشوند

چگونه؟

public int Calculate(int someInput)
{
    int Factorial(int i)
    {
        if (i <= 1)
            return 1;
        return i * Factorial(i - 1);
    }
    var input = someInput + ... // Other calcs
 
    return Factorial(input);
}

C# 7 Immutable Types

چیست؟

object های تغییر نا پذیر oblect هایی هستند که بعد از ساخته شدن تغییر نمیکنند.

Why?

oblect های تغییر ناپذیر چه مزایایی دارند:

• Inherently thread-safe

• به سادگی ایجاد می شوند

• ساده بودن برای موازی کردن کد ها 

• Reference هایی که به object های تغییر ناپذیر اشاره میکنند میتوانند cached بشوند.و تغییر نخواهند کرد.

در حال حاظر میتوانید یک  immutable objects را تعریف کنید.

public class Point
{
    public Point(int x, int y)
    {
        x = x;
        Y = y;
    }
 
    public int X { get; }
    public int Y { get; }
}

هنگامی که یک immutable object را معین میکنیم، مشکل انجاست که مفهوم واضحی ندارد.

ممکن است یکی  setter اضافه کند و استفاده کنندگان از این تایپ، همچنان انتظار immutability داشته باشند.

به این ترتیب می توان از آن ها، نتایج مختلفی را انتظار داشت.

چگونه؟

نکته: این syntax هم اکنون در حال استفاده است اما توصیه اساسی ما به شما اضافه کردن کلمه کلیدی immutable به syntax های رایج است.

public immutable class Point
{
    public Point(int x, int y)
    {
        x = x;
        Y = y;
    }
 
    public int X { get; }
    public int Y { get; }
}

وقتی شما از  immutable types استفاده میکنید ، ویژگی مفیدی در اختیار خواهید داشت که به شما اجازه ساخت نمونه های جدید مبتنی بر نمونه های مختلف قبلی را می دهد. 

var a = new Point(2, 5);
var b = a with { X = 1};

آموزش سی شارپ

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 2k بازدید
  • 2 تشکر

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

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید