• دستورات و موارد جدید در C# 9

    چه دستورات و مواردی در نسخه سی شارپ 9 c# اضافه شده است و این نسخه دارای چه پیشرفت هاییست...

    Records Type

    C# 9.0 انواع رکوردها را معرفی می کند . شما از recordکلمه کلیدی برای تعریف یک نوع مرجع استفاده می کنید که عملکرد داخلی را برای کپسوله کردن داده ها فراهم می کند. شما می توانید انواع رکورد با ویژگی های تغییرناپذیر را با استفاده از پارامترهای موقعیتی یا Typeویژگی استاندارد ایجاد کنید:

    public record Person(string FirstName, string LastName);
    public record Person
    {
        public required string FirstName { get; init; }
        public required string LastName { get; init; }
    };

    همچنین می توانید انواع رکورد با خواص و فیلدهای قابل تغییر ایجاد کنید:

    public record Person
    {
        public required string FirstName { get; set; }
        public required string LastName { get; set; }
    };

     

    در حالی که رکوردها می توانند تغییر پذیر باشند، آنها در درجه اول برای پشتیبانی از مدل های داده غیرقابل تغییر در نظر گرفته شده اند. نوع رکورد ویژگی های زیر را ارائه می دهد:

     

    • Typeمختصر برای ایجاد یک نوع مرجع با خواص تغییرناپذیر
    • رفتار مفید برای یک نوع مرجع داده محور:
      • برابری ارزشی
      • Typeمختصر برای جهش غیر مخرب
      • قالب بندی داخلی برای نمایش
    • پشتیبانی از سلسله مراتب وراثت

    می‌توانید از انواع ساختار برای طراحی انواع داده‌محور استفاده کنید که برابری ارزش و رفتار کم یا بدون رفتار را ارائه می‌دهند. اما برای مدل های داده نسبتاً بزرگ، انواع ساختار دارای معایبی هستند:

    • آنها از ارث حمایت نمی کنند.
    • آنها در تعیین برابری ارزش کارایی کمتری دارند. برای انواع مقادیر، متد ValueType.Equals از بازتاب برای یافتن تمام فیلدها استفاده می کند. برای رکوردها، کامپایلر Equalsمتد را تولید می کند. در عمل، اجرای برابری ارزش در رکوردها به طور قابل اندازه گیری سریعتر است.
    • آنها در برخی از سناریوها از حافظه بیشتری استفاده می کنند، زیرا هر نمونه یک کپی کامل از همه داده ها دارد. انواع رکوردها انواع مرجع هستند ، بنابراین یک نمونه رکورد فقط حاوی ارجاع به داده است.

    Positional syntax for property definition

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

    public record Person(string FirstName, string LastName);
    
    public static void Main()
    {
        Person person = new("Nancy", "Davolio");
        Console.WriteLine(person);
        // output: Person { FirstName = Nancy, LastName = Davolio }
    }

    هنگامی که از Typeموقعیتی برای تعریف ویژگی استفاده می کنید، کامپایلر ایجاد می کند:

    • یک ویژگی عمومی پیاده‌سازی خودکار فقط برای هر پارامتر موقعیتی ارائه شده در اعلان رکورد. یک ویژگی init-only را فقط می توان در سازنده یا با استفاده از یک اولیه کننده ویژگی تنظیم کرد.
    • یک سازنده اولیه که پارامترهای آن با پارامترهای موقعیتی در اعلام رکورد مطابقت دارد.
    • روشی Deconstructبا یک outپارامتر برای هر پارامتر موقعیتی ارائه شده در اعلان رکورد.

    تغییرناپذیری Immutability

    نوع رکورد لزوما تغییر ناپذیر نیست. می‌توانید ویژگی‌ها را با setدسترسی‌ها و فیلدهایی که نیستند اعلام کنید readonly. اما در حالی که رکوردها می توانند قابل تغییر باشند، ایجاد مدل های داده غیرقابل تغییر را آسان تر می کنند. ویژگی هایی که با استفاده از Typeموقعیتی ایجاد می کنید تغییر ناپذیر هستند.

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

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

    برابری ارزشی Value equality

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

    مثال زیر برابری مقدار انواع رکوردها را نشان می دهد:

    public record Person(string FirstName, string LastName, string[] PhoneNumbers);
    
    public static void Main()
    {
        var phoneNumbers = new string[2];
        Person person1 = new("Nancy", "Davolio", phoneNumbers);
        Person person2 = new("Nancy", "Davolio", phoneNumbers);
        Console.WriteLine(person1 == person2); // output: True
    
        person1.PhoneNumbers[0] = "555-1234";
        Console.WriteLine(person1 == person2); // output: True
    
        Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
    }

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

    جهش غیر مخرب Nondestructive mutation

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

    public record Person(string FirstName, string LastName)
    {
        public string[] PhoneNumbers { get; init; }
    }
    
    public static void Main()
    {
        Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
        Console.WriteLine(person1);
        // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
    
        Person person2 = person1 with { FirstName = "John" };
        Console.WriteLine(person2);
        // output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
        Console.WriteLine(person1 == person2); // output: False
    
        person2 = person1 with { PhoneNumbers = new string[1] };
        Console.WriteLine(person2);
        // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
        Console.WriteLine(person1 == person2); // output: False
    
        person2 = person1 with { };
        Console.WriteLine(person1 == person2); // output: True
    }

    قالب بندی داخلی برای نمایش Built-in formatting for display

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

    <record type name> { <property name> = <value>, <property name> = <value>, ...}

    برای انواع مرجع، به جای مقدار ویژگی، نام نوع شیئی که ویژگی به آن اشاره دارد نمایش داده می شود. در مثال زیر، آرایه یک نوع مرجع است، بنابراین System.String[]به جای مقادیر واقعی عنصر آرایه نمایش داده می شود:

    Person { FirstName = Nancy, LastName = Davolio, ChildNames = System.String[] }

    وراثت Inheritance

    یک رکورد می تواند از رکورد دیگری ارث ببرد. با این حال، یک رکورد نمی تواند از یک کلاس ارث بری کند، و یک کلاس نمی تواند از یک رکورد ارث بری کند.

    مثال زیر وراثت با Typeویژگی موقعیتی را نشان می دهد:

    public abstract record Person(string FirstName, string LastName);
    public record Teacher(string FirstName, string LastName, int Grade)
        : Person(FirstName, LastName);
    public static void Main()
    {
        Person teacher = new Teacher("Nancy", "Davolio", 3);
        Console.WriteLine(teacher);
        // output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
    }

    برای اینکه دو متغیر رکورد برابر باشند، نوع زمان اجرا باید برابر باشد. انواع متغیرهای حاوی ممکن است متفاوت باشد. این در مثال کد زیر نشان داده شده است:

    public abstract record Person(string FirstName, string LastName);
    public record Teacher(string FirstName, string LastName, int Grade)
        : Person(FirstName, LastName);
    public record Student(string FirstName, string LastName, int Grade)
        : Person(FirstName, LastName);
    public static void Main()
    {
        Person teacher = new Teacher("Nancy", "Davolio", 3);
        Person student = new Student("Nancy", "Davolio", 3);
        Console.WriteLine(teacher == student); // output: False
    
        Student student2 = new Student("Nancy", "Davolio", 3);
        Console.WriteLine(student2 == student); // output: True
    }

     

    در مثال، همه نمونه‌ها دارای ویژگی‌های یکسان و مقادیر ویژگی یکسان هستند. اما student == teacherباز می گرداند Falseاگرچه هر دو Personمتغیر نوع - هستند. و student == student2برمی گرداند Trueاگرچه یک Personمتغیر و یکی Studentمتغیر است.

     

    تمام خصوصیات عمومی و فیلدهای هر دو نوع مشتق شده و پایه در خروجی گنجانده شده است ToString، همانطور که در مثال زیر نشان داده شده است:

    public abstract record Person(string FirstName, string LastName);
    public record Teacher(string FirstName, string LastName, int Grade)
        : Person(FirstName, LastName);
    public record Student(string FirstName, string LastName, int Grade)
        : Person(FirstName, LastName);
    
    public static void Main()
    {
        Person teacher = new Teacher("Nancy", "Davolio", 3);
        Console.WriteLine(teacher);
        // output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
    }

    تنظیم کننده Init only setters

    تنظیم‌کننده‌های Init فقط نحوی سازگار برای مقداردهی اولیه اعضای یک شی فراهم می‌کنند. مقداردهی اولیه مشخص می کند که کدام مقدار کدام ویژگی را تنظیم می کند. نکته منفی این است که آن ویژگی ها باید قابل تنظیم باشند. با شروع با C# 9.0، می توانیدinitبه جایsetدسترسی به ویژگی ها و نمایه سازها، Accessorهایی ایجاد کنید. فراخوان‌کنندگان می‌توانند از Typeتنظیم‌کننده ویژگی برای تنظیم این مقادیر در عبارات ایجاد استفاده کنند، اما این ویژگی‌ها فقط پس از تکمیل ساخت‌وساز قابل خواندن هستند. تنظیم کننده های init only پنجره ای برای تغییر حالت ارائه می دهند. وقتی مرحله ساخت و ساز به پایان می رسد، آن پنجره بسته می شود. مرحله ساخت و ساز به طور موثر پس از اتمام تمام مقداردهی اولیه، از جمله مقداردهی اولیه و با بیان، به پایان می رسد.

    شما می توانید initفقط تنظیم کننده ها را در هر نوع که بنویسید اعلام کنید. به عنوان مثال، ساختار زیر یک ساختار رصد آب و هوا را تعریف می کند:

    public struct WeatherObservation
    {
        public DateTime RecordedAt { get; init; }
        public decimal TemperatureInCelsius { get; init; }
        public decimal PressureInMillibars { get; init; }
    
        public override string ToString() =>
            $"At {RecordedAt:h:mm tt} on {RecordedAt:M/d/yyyy}: " +
            $"Temp = {TemperatureInCelsius}, with {PressureInMillibars} pressure";
    }

    تماس‌گیرندگان می‌توانند از دستور اولیه ویژگی برای تنظیم مقادیر استفاده کنند، در حالی که همچنان تغییر ناپذیری را حفظ می‌کنند:

    var now = new WeatherObservation 
    { 
        RecordedAt = DateTime.Now, 
        TemperatureInCelsius = 20, 
        PressureInMillibars = 998.0m 
    };

    تلاش برای تغییر یک مشاهده پس از مقداردهی اولیه منجر به یک خطای کامپایلر می شود:

    // Error! CS8852.
    now.TemperatureInCelsius = 18;

    تنظیم کننده های init only می توانند برای تنظیم ویژگی های کلاس پایه از کلاس های مشتق شده مفید باشند. آنها همچنین می توانند ویژگی های مشتق شده را از طریق کمک کننده ها در یک کلاس پایه تنظیم کنند. رکوردهای موقعیتی با استفاده از تنظیم کننده های init only مشخص می کنند. این تنظیم کننده ها در با بیان استفاده می شوند. شما می توانید تنظیم کننده های init only را برای هر class, structیا recordتعریفی که تعریف می کنید، اعلام کنید.

    برای اطلاعات بیشتر، init (مرجع C#) را ببینید .

    بیانیه های سطح بالا Top-level statements

    بیانیه های سطح بالا مراسم غیر ضروری را از بسیاری از برنامه ها حذف می کند. "سلام جهان!" را در نظر بگیرید. برنامه:

    using System;
    
    namespace HelloWorld
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World!");
            }
        }
    }

     

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

     

    using System;
    
    Console.WriteLine("Hello World!");

    اگر می‌خواهید یک برنامه تک خطی داشته باشید، می‌توانید usingدستورالعمل را حذف کنید و از نام نوع کاملاً واجد شرایط استفاده کنید:

    System.Console.WriteLine("Hello World!");

    فقط یک فایل در برنامه شما ممکن است از عبارات سطح بالا استفاده کند. اگر کامپایلر عبارات سطح بالایی را در چندین فایل منبع پیدا کند، خطا است. همچنین اگر عبارات سطح بالا را با روش نقطه ورود برنامه اعلام شده ترکیب کنید، معمولاً یک Mainروش، یک خطا است. به یک معنا، می توانید فکر کنید که یک فایل حاوی عباراتی است که معمولاً در Mainمتد یک Programکلاس وجود دارد.

    یکی از رایج ترین کاربردهای این ویژگی ایجاد مواد آموزشی است. توسعه دهندگان مبتدی سی شارپ می توانند "Hello World!" را بنویسند. در یک یا دو خط کد هیچ یک از مراسم اضافی لازم نیست. با این حال، توسعه دهندگان باتجربه کاربردهای زیادی برای این ویژگی نیز پیدا خواهند کرد. عبارات سطح بالا تجربه ای شبیه به اسکریپت را برای آزمایش مشابه آنچه که نوت بوک های Jupyter ارائه می دهند، امکان پذیر می کند. بیانیه های سطح بالا برای برنامه ها و برنامه های کاربردی کنسول کوچک عالی هستند. Azure Functions یک مورد استفاده ایده آل برای عبارات سطح بالا است.

    مهمتر از همه، عبارات سطح بالا دامنه یا پیچیدگی برنامه شما را محدود نمی کند. این عبارات می توانند به هر کلاس دات نت دسترسی داشته باشند یا از آنها استفاده کنند. آنها همچنین استفاده شما از آرگومان های خط فرمان یا مقادیر بازگشتی را محدود نمی کنند. عبارات سطح بالا می توانند به آرایه ای از رشته ها با نام دسترسی داشته باشند args. اگر عبارات سطح بالا یک مقدار صحیح را برگردانند، آن مقدار به کد برگشتی عدد صحیح از یک Mainمتد سنتز شده تبدیل می شود. عبارات سطح بالا ممکن است حاوی عبارات ناهمگام باشند. در آن صورت، نقطه ورودی سنتز شده یک Task، یا را برمی گرداند Task<int>.

     

    پیشرفت های تطبیق الگو Pattern matching enhancements

    C# 9 شامل بهبودهای تطبیق الگوی جدید است:

    • Type patterns منطبق با یک شی مطابق با یک نوع خاص است
    • Parenthesized patterns بر تقدم ترکیب الگوها اعمال یا تأکید می کنند
    • Conjunctive and patterns نیاز به تطابق هر دو الگو دارند
    • Disjunctive or patterns نیاز به هر یک از الگوها برای مطابقت دارند
    • Negated not patterns مستلزم این است که یک الگو مطابقت نداشته باشد
    • Relational patterns نیاز دارند که ورودی کمتر از، بزرگتر، کمتر یا مساوی، یا بزرگتر یا مساوی یک ثابت معین باشد.

    این الگوها Typeالگوها را غنی می کنند. این نمونه ها را در نظر بگیرید:

    public static bool IsLetter(this char c) =>
        c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';

    با پرانتز اختیاری برای اینکه مشخص شود andاولویت بیشتری نسبت به or:

    public static bool IsLetterOrSeparator(this char c) =>
        c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',';

    یکی از رایج ترین استفاده ها، یک Typeجدید برای بررسی تهی است:

    if (e is not null)
    {
        // ...
    }

    هر یک از این الگوها را می توان در هر زمینه ای که الگوها مجاز هستند استفاده کرد: isعبارات الگو، switchعبارات، الگوهای تودرتو، و الگوی برچسب یک switchعبارت case.

    عملکرد Performance و Interop

    سه ویژگی جدید پشتیبانی از کتابخانه های داخلی و سطح پایین را که به عملکرد بالا نیاز دارند بهبود می بخشد: اعداد صحیح با اندازه بومی، نشانگرهای تابع، و حذف پرچم localsinit.

    اعداد صحیح با اندازه بومی nintو nuint, انواع عدد صحیح هستند. آنها با انواع زیربنایی System.IntPtr و System.UIntPtr بیان می شوند . کامپایلر تبدیل‌ها و عملیات‌های اضافی را برای این انواع به‌عنوان intهای داخلی نشان می‌دهد. اعداد صحیح با اندازه بومی ویژگی ها را برای MaxValueیا تعریف می کنند MinValue. این مقادیر را نمی توان به عنوان ثابت های زمان کامپایل بیان کرد زیرا به اندازه اصلی یک عدد صحیح در ماشین هدف بستگی دارد. این مقادیر در زمان اجرا فقط خواندنی هستند. می توانید از مقادیر ثابت برای nintدر محدوده [ int.MinValue.. int.MaxValue] استفاده کنید. می توانید از مقادیر ثابت برای nuintدر محدوده [ uint.MinValue.. uint.MaxValue] استفاده کنید. کامپایلر با استفاده از System.Int32، تاشوی ثابتی را برای تمام عملگرهای یونری و باینری انجام می دهدو انواع System.UIint32 . اگر نتیجه در 32 بیت قرار نگیرد، عملیات در زمان اجرا اجرا می شود و ثابت در نظر گرفته نمی شود. اعداد صحیح با اندازه بومی می توانند عملکرد را در سناریوهایی افزایش دهند که از ریاضی اعداد صحیح به طور گسترده استفاده می شود و باید سریع ترین عملکرد ممکن را داشته باشند. برای اطلاعات بیشتر، nintو nuintانواع را ببینید .

    نشانگرهای تابع یک Typeساده برای دسترسی به کدهای عملیاتی IL ldftnو calli. شما می توانید نشانگرهای تابع را با استفاده از delegate*Typeجدید اعلام کنید. نوع یک delegate*نوع اشاره گر است. فراخوانی delegate*نوع استفاده می‌کند calli، برخلاف نماینده‌ای که callvirtاز Invoke()متد استفاده می‌کند. از نظر نحوی، فراخوان ها یکسان هستند. فراخوانی نشانگر تابع از managedقرارداد فراخوانی استفاده می کند. شما unmanagedکلمه کلیدی را بعد از delegate*Typeاضافه می کنید تا اعلام کنید که کنوانسیون فراخوانی را می خواهید unmanaged. سایر قراردادهای فراخوانی را می توان با استفاده از ویژگی های موجود در delegate*اعلان مشخص کرد. برای اطلاعات بیشتر، کد ناامن و انواع نشانگر را ببینید .

    در نهایت، می توانید System.Runtime.CompilerServices.SkipLocalsInitAttribute را اضافه کنید تا به کامپایلر دستور دهید که localsinitپرچم را منتشر نکند. این پرچم به CLR دستور می دهد تا تمام متغیرهای محلی را صفر اولیه کند. پرچم localsinitاز 1.0 رفتار پیش فرض برای C# بوده است. با این حال، صفر اولیه اضافی ممکن است در برخی از سناریوها تأثیر عملکرد قابل اندازه گیری داشته باشد. به طور خاص، زمانی که از stackalloc. در این موارد، می‌توانید SkipLocalsInitAttribute را اضافه کنید . می‌توانید آن را به یک متد یا ویژگی، یا به یک class،،، یا حتی یک ماژول structاضافه کنید. این ویژگی روی روش‌ها interfaceتأثیری ندارد . abstractبر روی کد تولید شده برای پیاده سازی تأثیر می گذارد. برای اطلاعات بیشتر، SkipLocalsInitویژگی را ببینید .

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

    ویژگی های تناسب و تکمیل Fit and finish features

    بسیاری از ویژگی های دیگر به شما کمک می کند تا کد را کارآمدتر بنویسید. در سی شارپ 9.0، زمانی که نوع شی ایجاد شده از قبل مشخص باشد، می توانید نوع را در یک newعبارت حذف کنید. رایج ترین استفاده در اعلانات میدانی است:

    private List<WeatherObservation> _observations = new();
    

    Target-typed newهمچنین می تواند زمانی استفاده شود که شما نیاز به ایجاد یک شی جدید برای ارسال به عنوان آرگومان به یک متد دارید. ForecastFor()روشی را با امضای زیر در نظر بگیرید :

    public WeatherForecast ForecastFor(DateTime forecastDate, WeatherForecastOptions options)
    

    می توانید آن را به صورت زیر صدا کنید:

    var forecast = station.ForecastFor(DateTime.Now.AddDays(2), new());
    

    یکی دیگر از کاربردهای خوب این ویژگی، ترکیب آن با خصوصیات init only برای مقداردهی اولیه یک شی جدید است:

    WeatherStation station = new() { Location = "Seattle, WA" };

    شما می توانید یک نمونه ایجاد شده توسط سازنده پیش فرض را با استفاده از یک return new();دستور برگردانید.

    یک ویژگی مشابه وضوح نوع هدف عبارات شرطی را بهبود می بخشد . با این تغییر، این دو عبارت نیازی به تبدیل ضمنی از یکی به دیگری ندارند، اما ممکن است هر دو تبدیل ضمنی به یک نوع هدف داشته باشند. احتمالاً متوجه این تغییر نخواهید شد. چیزی که متوجه خواهید شد این است که برخی از عبارات شرطی که قبلاً به بازیگران نیاز داشتند یا اکنون کامپایل نمی شدند، فقط کار می کنند.

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

    انواع بازده کوواریانت انعطاف پذیری را برای انواع برگشتی روش های نادیده گرفتن فراهم می کند . یک متد override می‌تواند یک نوع مشتق شده از نوع برگشتی روش پایه بازگردانی شده را برگرداند. این می تواند برای رکوردها و سایر انواعی که از روش های شبیه سازی مجازی یا کارخانه پشتیبانی می کنند مفید باشد.

    علاوه بر این، foreachحلقه یک متد بسط را تشخیص داده و از آن استفاده می کند GetEnumeratorکه در غیر این صورت foreachالگو را برآورده می کند. این معنی تغییر foreachبا سایر ساختارهای مبتنی بر الگو مانند الگوی همگام و ساختارشکنی مبتنی بر الگو سازگار است. در عمل، این تغییر به این معنی است که می توانید foreachبه هر نوع پشتیبانی اضافه کنید. شما باید استفاده از آن را به زمانی محدود کنید که شمارش یک شی در طراحی شما منطقی است.

    در مرحله بعد، می توانید از رد کردن ها به عنوان پارامترهای عبارات لامبدا استفاده کنید. این راحتی شما را قادر می سازد از نامگذاری آرگومان خودداری کنید و کامپایلر ممکن است از استفاده از آن اجتناب کند. شما از آن _برای هر استدلالی استفاده می کنید. برای اطلاعات بیشتر، به پارامترهای ورودی بخش عبارت lambda در مقاله عبارات لامبدا مراجعه کنید .

    در نهایت، اکنون می‌توانید ویژگی‌ها را برای توابع محلی اعمال کنید . به عنوان مثال، می توانید حاشیه نویسی صفت تهی را برای توابع محلی اعمال کنید.

    پشتیبانی از تولید کننده کد Support for code generators

    دو ویژگی نهایی از تولید کننده کد C# پشتیبانی می کنند. مولدهای کد سی شارپ کامپوننتی هستند که می توانید بنویسید و شبیه به تحلیلگر roslyn یا رفع کد است. تفاوت این است که مولدهای کد کد را تجزیه و تحلیل می کنند و فایل های کد منبع جدید را به عنوان بخشی از فرآیند کامپایل می نویسند. یک مولد کد معمولی کد را برای ویژگی ها یا قراردادهای دیگر جستجو می کند.

    یک مولد کد ویژگی ها یا سایر عناصر کد را با استفاده از API های تحلیل Roslyn می خواند. از این اطلاعات، کد جدیدی به کامپایل اضافه می کند. مولدهای منبع فقط می توانند کد اضافه کنند. آنها مجاز به تغییر هیچ کد موجود در کامپایل نیستند.

    دو ویژگی اضافه شده برای مولدهای کد عبارتند از پسوندهای نحوی روش جزئی و مقداردهی اولیه ماژول . اول، تغییرات به روش های جزئی. قبل از C# 9.0، متدهای جزئی هستند privateاما نمی توانند یک اصلاح کننده دسترسی را مشخص کنند، voidبازگشتی دارند و نمی توانند outپارامتر داشته باشند. این محدودیت ها به این معنی است که اگر هیچ روشی برای پیاده سازی ارائه نشود، کامپایلر همه فراخوانی های متد جزئی را حذف می کند. C# 9.0 این محدودیت‌ها را حذف می‌کند، اما مستلزم آن است که اعلان‌های روش جزئی دارای پیاده‌سازی باشند. تولیدکنندگان کد می توانند آن پیاده سازی را ارائه دهند. برای جلوگیری از ایجاد تغییر شکست، کامپایلر هر روش جزئی و بدون اصلاح کننده دسترسی را برای پیروی از قوانین قدیمی در نظر می گیرد. اگر روش جزئی شاملprivateاصلاح کننده دسترسی، قوانین جدید بر آن روش جزئی حاکم است. برای اطلاعات بیشتر، روش جزئی (مرجع C#) را ببینید .

    دومین ویژگی جدید برای تولیدکنندگان کد، اولیه سازهای ماژول است . مقداردهی اولیه ماژول متدهایی هستند که ویژگی ModuleInitializerAttribute به آنها متصل است. این متدها قبل از هر دسترسی فیلد دیگر یا فراخوانی متد در کل ماژول توسط زمان اجرا فراخوانی می شوند. یک روش اولیه ماژول:

    • باید ثابت باشد
    • باید بدون پارامتر باشد
    • باید باطل برگردد
    • نباید یک روش عمومی باشد
    • نباید در یک کلاس عمومی قرار گیرد
    • باید از ماژول حاوی قابل دسترسی باشد
    نظرات ارسال شده ارسال نظر جدید
    برای تبادل نظر، می بایست در سایت وارد شوید

    ورود به سایت
تماس سبد خرید بالا