تازههای C# ۶.0
چهارشنبه 23 مهر 1393C# ۶ یک سری خصوصیت جدیدی را در خود دارد که به وسیله آن کار برنامه نویسان از بابت کد نویسی زبانهای مختلف بسیار راحت تر میشود.c# ۶ کامپایلر جدیدی به نام "Roslyn" دارد که به ما این امکان را میدهد که کامپایلر را به کار بگیریم و رفتارهای مهم کامپایلر را همان طور که برای برنامهٔ خودمان نیاز داریم تغییر دهیم.
از چندین سال قبل تا به امروز،مایکروسافت در حل کار کردن روی این موضوع بوده که بتواند کامپایلر C# و VB را باز نویسی کند.حالا بعد از چندین سال این کار را انجام داده و این خبر به عنوان یک سورپرایز بزرگ به تازگی و زمانی منتشر شده است که مایکروسافت اعلام کرده است که کامپایلرهای جدید خود را به صورت open source ارائه میدهد.این گفته ، نه تنها به این معناست که کاری که آنها انجام میدهند واضح است ، بلکه آنها میتوانند بازخورد مناسبی هم از کاری که میکنند ارائه دهند.
از آنجایی که documentهای طراحی زبان در سایت CodePlex وجود دارند،هر برنامه نویسی هر زمانی که تصمیم بگیرد،میتواند از این خصوصیات جدید استفاده کند.
با استفاده از باز نویسی کامپایلر C# و VB ،کار تیم طراحی زبان برای اضافه کردن جنبه ها و خصوصیات جدید به زبان مربوطه بسیار راحت تر میشود .با توجه به اینکه هزینه اضافه کردن یک feature جدید به طور قابل ملاحظه ای کمتر از چیزی است که قبلا با کامپایلر بوده،تیم طراحی زبان میتواند روی این قضیه تمرکز کند و زندگی را برای ما برنامه نویسان بسیار راحت تر کند و این لزوما به این معنی نیست که همه چیز را از منظر runtime تغییر دهند.
راهنمای پرسش و پاسخ ( FAQ Book) بسیار عالی NET.
تا قبل از امروز، تمام کامپایلرهای C# و VB از دید مصرف کنندگان مانند یک جعبه سیاه بودند.این جعبه سیاه یک syntax را به چیزی که قابل اجرا باشد یا چیزی که بتوانیم به سادگی به آن refrence بدهیم ترجمه می کرد.این امر کارایی کامپایلر را محدود میکرد ،که البته ما با آن مشکلی نداشتیم.هرچند،شگفت زده می شوید وقتی به این موضوع فکر کنید که چه فرصتهایی ایجاد می شود،زمانی که یک کامپایلر داریم که تماما open است و برای مصرف کنندهها قابل دسترسی است.
قبل از اینکه به این بپردازیم که ورژن جدید C# چگونه است ،بیایید فکر کنیم به اینکه این تغییرات چه کاری با ما خواهند کرد،یعنی با مصرف کنندگان کامپایلر.
Codename Roslyn
مایکروسافت به کامپایلرهای جدیدش codename ای به نام "Roslyn" را داده است.
تغییراتی که مربوط به رفتار کامیاپلر است به عنوان analysis و refactor کردن pluginها شناخت می شود.هنگامی که آن را انتخاب میکنید و Roslyn را install میکنید ، sample کدها و solutionها را خواهید داشت.یکی از این sampleها به شما این امکان را می دهد که اگر solution شما حاوی declarationهایی باشد که بتواند به مقدار ثابتی convert شود، از آن آگاه شوید.
sample دیگر به شما این امکان را میدهد که اسم متغیر هایی را که شامل کاراکترهای مشخصی هست پیدا کنید. این کار برای یادگیری این است که بدانید APIهای کامپایلر چگونه کار میکنند.
این مقاله در مورد این نیست که ما چگونه این نوع از pluginها را مینویسیم،دانستن اینکه تاثیر داشتن یک کامپایلری که برای #C و VB دوباره نوشته شده است ( re-written compiler ) برای ما اهمیت دارد، همانطور که کار را برای مصرف کنندگان راحت تر میکند تا با کامپایلر interop داشته باشند و process هایی را آنالیز کنند،کار مایکروسافت هم برای شناساندن feature های زبان و درست کردن bug های ممکن در زبان، راحت تر شده است. بنا بر این کار مایکروسافت از جهت اینکه بتواند روی اینکه بهترین تجربیات ممکن در هنگام استفادهٔ برنامه نویسان #C و VB را هنگام استفاده از زبانهایشان به آنها بدهد، تمرکز کند ، راحت تر شده است.
این تغییرات همانهایی هستند که در ابتدای این مقاله توضیح دادیم،بعضی از آنها ممکن است که در ورژن بعدی نباشند،بعضی از آنها هم هم اکنون پیاده سازی شده اند و آماده ی استفاده هستند.از آنجایی که Roslyn ،متن باز است و در سایت codePlex قابل دسترسی است ،مایکروسافت از گروههای مختلفی دعوت کرده تا نظرات خود را در مورد طراحی ای که کرده اند بیان کنند و واقعا هم به نظرات گروههای #C و VB توجه میکنند.
تازههای C# 6.0 a.k.a
لزوما احتیاجی نیست که keyword های جدید را در ورژن جدید #C ببینیم، اما تفاوت معنایی را خواهیم دید که کار را برای برنامه نویسان راحت میکند تا از کد نویسیهای مختلف جلوگیری کند.
از آنجایی که ورژن جدید کامپایلر هنوز در حال سخت و توسعه است،ممکن است بعضی از feature های زبان گرفته شود، بعضی از آنها ممکن است اضافه شوند و بعضی از آنها ممکن است که با تاخیر در ورژن بعدی آورده شوند.
سیر تکاملی #C مدرکی است بر اینکه این زبان زنده خواهد ماند و مردم از آن استفاده میکنند و او برای ماندن مبارزه میکند.
Constructorهای اصلی
از قدیم تا به الان ، شما Constructorهایی ساخته اید که به سادگی مقادیر را به فیلدهای private منتقل میکردند تا بعدا در کلاس از آنها استفاده شود. در نظر بگیرید که کلاسی داریم مربوط به یک شخص، هر شخص باید نام و سنّ داشته باشد.(همین اطلاعات فعلا برای ما کافیست! )
constructor شخص میتواند به روش سادهای نوشته شود.همان طور که در کد زیر میبینید ، ما نیاز به هیچ validation خاصی روی داده ای که به constructor پاس داده می شود نداریم.
public Person(string name, int age) { _name = name; _age = age; }
اکنون راه بسیار آسان تری برای تعریف کلاسهایمان و constructorهای اصلی آن داریم.این امر به این نیاز دارد که از محدوده constructor خارج شویم و signature کلاس را تغییر دهیم.حالا مقداری از آنچه که قبلا در #C استفاده میکردیم فاصله میگیریم.
باید signature کلاس را تغییر دهیم تا پارامترهایی را داشته باشیم که برای داشتن Constructor اصلی میخواهیم.در این جا ما نام و سنّ را داریم.در زیر کدی را که میبینیم همان چیزی است که کلاس ما هم اکنون شبیه به آن است:
class Person(string name, int age) { private string _name = name; private int _age = age; }
پارامترهایی که در Constructor اصلی تعریف کردیم ، روی declaration کلاس قرار میگیرد ، احتیاج داریم که اینها را به متغیرهای instance اختصاص دهیم. بعد از این میتونیم از متغیرهای instance _name و age_ استفاده کنیم، مانند هر متغیر instance معمولی دیگر.
اگر میخواهید بیشتر از یک constructor داشته باشید،باید در declaration کلاس چیزهایی را که بیشتر استفاده میکنیم تعریف کنیم و سپس بقیهٔ constructorها را تعریف کنیم. نمونه کد زیر را ببینید:
class Person(string name, int age) { private string _name = name; private int _age = age; private string _address; public Person(string name, int age, string address) : this(name, age) { _address = address; } public void Speak() { Console.WriteLine("Hi, my name is {0} and I am {1} years old", _name, _age); } }
به اندازهٔ کافی جالب است اگر در refactor ، اسمبلیهای کامپایل شده را باز کنیم و بررسی کنیم که چه کدی به وسیلهٔ کامپایلر ایجاد شده است،خواهیم دید که فقط همان کدی است که قبلا هم می دیدیم،این به این منا است که در واقع نیازی به تفاوت در زمان اجرا نیست.
internal class Person { private string _address; private int _age; private string _name; public Person(string name, int age) { this._name = name; this._age = age; } public Person(string name, int age, string address) : this(name, age) { this._address = address; } public void Speak() { Console.WriteLine("Hi, my name is {0} and I am {1} years old", this._name, this._age); } }
Auto-properties
propertyها به صورت متداول در #C استفاده می شوند ،ممکن است فکر کنید هیچ بهینه سازی ای صورت نگرفته است.
به هر حال، با معرفی constructor اصلی ما به راهی نیاز داریم تا بتوانیم propertyهایی را که ممکن است در نمونهٔ کلاسمان بخواهیم، initialize کنیم.
همان طور که در نمونه کد زیر میبینید،به آسانی بیان کرده ایم که property برابر با مقداری است که ما به آن میدهیم.
class Person(string name, int age) { public string Name { get; set; } = name; }
همچنین این کار برای کسانی که فقط گیرنده هستند هم عمل میکند،همان طور که در کد زیر میبینید:
class Person(string name, int age) { public string Name { get; } = name; }
ما میدانیم که به وسیلهٔ فیلدها برگردانده میشوند و همین امر هم در اینجا اتفاق میافتد ، اما کامپایلر آن را برای ما handle میکند.با نگاه کردن به کد تولید شده بوسیلهٔ کامپایلر، خواهیم دید که مقدار دهی اوّلیه به constructor اصلی صورت میگیرد و فیلدهای بازگشتی propertyها به مقدار صحیحی set میشود.
private readonly string <Name>k__BackingField; public string Name { get { return this.<Name> k__BackingField; } } public Person(string name, int age) { this.<Name> k__BackingField = name; this._age = age; }
initializerهای auto-property ، همراه با constructorهای اصلی ،به ما این امکان را میدهند که از نوشتن کدهای مختلف پرهیز کنیم.زیاد نیست اما باعث ایجاد فرق بسیاری میشود.
Using statement برای static member ها
اگر از یک عضو static زیاد استفاده میکنید ،پس می دانید که همیشه باید اسم کلاس یا مسیر static member را مرتبا تکرار کنید.مسلما خیلی بهتر بود اگر میتوانستیم کلاسهای static member را به عنوان قسمتی از type خودمان در نظر بگیریم و تعریف کنیم،که در نتیجه یه این کار دسترسی ما به متدها هم راحت تر میشد.استفاده از Debug را در نظر بگیرید.یا برای مثال استفاده از WriteLine یا Console.WriteLine . آیا بهتر نبود اگر میتوانستیم تعریف کنیم که تمام static memberهای debug و console را داریم که میتاونیم از آنها در کلاسمان استفاده کنیم ،بدون اینکه به static member مسیر کامل را بدهیم؟
همان طور که در کد کوتاه زیر میبینید،این کاریست که ما در ورژن جدید #C میتونیم انجام دهیم.به سادگی تعریف کرده ایم که میخواهیم از System.Console استفاده کنیم و فقط هم باید WriteLine را به جای نوشتن مسیر کامل بنویسیم.
using System.Console; class Person(string name, int age) { public string Name { get; } = name; private int _age = age; public void Speak() { WriteLine("Hi, my name is {0} and I am {1} years old", Name, _age); } }
از طرف دیگر این تغییر ،کدهای مختلفی را که همیشه باید مینوشتیم را از بین برده است. سود دیگری که دارد این است که ما میتوانیم خیلی راحت تر swap کنیم که کدام WriteLine برای debug استفاده شده است. WriteLine مخالف console عمل میکند. WriteLine به معنی این است که ما باید using statmenet را عوض کنیم. البته ، میتوانیم همان متد را درون کلاسمان تعریف کنیم و در این صورت به جای متد static از آن استفاده خواهد شد.این به این معنی است که اگر ما یک متدی را تعریف کنیم که WriteLine را با همان پارامتر به عنوان static memberای که قبلا به آن دسترسی داشتیم صدا بزند، متدی که در کلاسمان بود به جای آن استفاده خواهد شد.
شما این کار را فقط برای کلاسهای static میتوانید انجام دهید، بنا بر این نمی توانید برای instance System.DateTime از using استفاده کنید.
Dictionary initializer
هنگامی که از dictionaryها استفاده میکنید،گاهی اوقات میخواهید همانند کاری که با لیستها و آرایه ها انجام میدهید ، dictionaryها را هم با value مورد نظرتان مقدار دهی اوّلیه کنید.قبلا هم میتوانستیم این کار را انجام دهیم البته با کمی تفاوت،اما حالا با استفاده از چیزی به نام dictionary initializer که خیلی شبیه به مقدار دهی اوّلیه به آرایه ها است این کار انجام می شود.
در کد زیر میبینید که این initializer جدید حتی با instance variableها هم کار میکند .
class Person(string name) { private Dictionary<string, string> _data = new Dictionary<string, string> {["Name"] = name }; }
حتی با auto-property initializerها که در همین مقاله در مورد آن توضیح دادیم هم کار میکند.
class Person(string name, int age) { public Dictionary<string, string> Data { get; } = new Dictionary<string, string> {["Name"] = name }; }
Declaration expressions
آیا تا به حال با کلمهٔ کلیدی out مواجه شده اید؟در این صورت میدانید که باید قبل از اینکه از آن در فراخوانی متد استفاده کنید، آن را تعریف کنید،جایی که پارامتر out وجود دارد.به دلایل مختلف ،شخصاً میگویم که بهتر است به جای اینکه در خط قبل آن را تعریف کنید، در همان خطی که متغییر را ایجاد میکنید این کار را انجام دهید.
کد زیر را در نظر بگیرید،به صورت معمول شما باید متغیر را قبل از فراخوانی متد تعریف کرده باشید.
public void CalculateAgeBasedOn(int birthYear, out int age) { age = DateTime.Now.Year - birthYear; }
ممکن است مثل کد کوتاهی که در زیر میبینید عمل کنید،که هنوز چیزی نیست که اشتباه باشد ولی جریان کار را خراب میکند:
int age; CalculateAgeBasedOn(1987, out age);
به جای کد بالا میتونیم از روش زیر استفاده کنیم و متغیر را در هم خط ایجاد کنیم:
CalculateAgeBasedOn(1987, out var age);
با این کار به جای ۲خط ،یک خط کد داریم.اگر به کدی که کامپایلر تولید میکند نگاه کنید میبینید که همان کد اول را تولید میکند، جایی که متغیر را قبل از فراخوانی تعریف میکردیم. خیلی خوب است که ما به عنوان برنامه نویس مجبور نیستیم این کار خسته کنند را انجام دهیم !!
استفاده از await در catch یا در بلاک finally
اگر تا به حال گرفتار async و await شده اید ، ممکن است تجربه کرده باشید که به دلایلی بخواهید در بلاک catch یا finally از await استفاده کنید.استفاده از APIهای async خیلی رایج شده اند تا جایی که در .net ۴.۵. به راحتی میتوان از آنها استفاده کرد. با متداول شدن این امر،ما به راهی نیاز داریم که تضمین کند که این امر با سناریوهای مختلف دیگر هم همخوانی دارد.
log گرفتن از یک instance را در نظر بگیرید. ممکن است بخواهید هنگامی که یک error را catch میکنید ، یک فایل log بنویسید اما برای مدت زیادی توقف صورت نگیرد.در این سناریو عالی میشود اگربتوانید درون catch, فراخوانی async را با مقداری delay توسط await انجام دهید.
به علاوه وقتی در مورد بلاک finally صحبت میکنیم، ممکن است بخواهیم بعضی resourceها را پاک کنیم یا اینکه کار به خصوصی در بلاک finally انجام دهیم که بخواهیم asynchronous API را فراخوانی کنیم.همان طور که در کد زیر میبینید ، این امر میسر شده است:
public async Task DownloadAsync() { try {} catch { await Task.Delay(2000); } finally { await Task.Delay(2000); } }
فیلتر کردن Exceptionها به وسیله Exception Filter ها
هنگامی که exceptionای را catch میکنیم ، ممکن است بخواهید exceptionها را به صورت مختلفی بر پایه severity در instance ، مدیریت کنید.البته این روش قبلا هم بوده است به وسیلهٔ نوشتن کدهای شرطی (conditional code ها) درون بلاک catch . اگرچه اگر میتوانستیم exceptionها را فیلتر کنیم ساده تر نبود؟مسلما همین طور است و این کار به وسیلهٔ Exception filterها انجام میگیرد
همان طور که در کد زیر میبینید به اسانی بعد از این که میگوئیم کدام exception را catch کنیم ، فیلتر را اعمال میکنیم.
try { throw new CustomException { Severity = 100 }; } catch (CustomException ex) if (ex.Severity > 50) { Console.WriteLine("*BING BING* WARNING *BING BING*"); }
برای کار کردن این مثال،یک کلاس به نام CustomException نیاز است که فقط یک property با نام severity در آن وجود دارد.در این مثال، ما به دنبال severity بالای ۵۰ هستیم.حالا اگر severity زیر ۵۰ باشد چه میشود؟نمیتوان exception را گرفت. برای اصلاح کردن آن میتوانیم یک بلاک catch دیگر بعد از قبلی تعریف کنیم .
try { throw new CustomException { Severity = 100 }; } catch (CustomException ex) if (ex.Severity > 50) { Console.WriteLine("*BING BING* WARNING *BING BING*"); } catch (CustomException ex) { Console.WriteLine("Whooops!"); }
این را به خاطر داشته باشید که باید به ترتیب نزولی به آنها دستور داده شود.در کد زیر میبینید که اولی خاصترین آن است و همین طور که پائین میرویم کم اهمّیتترین فیلترها راداریم.
catch (CustomException ex) if (ex.Severity > 50) {} catch (CustomException ex) if (ex.Severity > 25) {} catch (CustomException ex) {} catch (Exception ex) {}
ویژگیهای برنامه ریزی شده در #C ۶.۰
تا الان نگاهی داشتیم به ویژگی هایی که در کامپایلر جدید به وجود آمده بود،ویژگی هایی که میتوانید با دانلود extension برای visual studio یا install کردن CTP برای visual studio ۱۴ آنها را تجربه کنید.اگرچه ویژگی های بیشتری هم وجود دارد که در مورد بعضی از آنها از ابتدای طراحی زبان صحبت شد اما بعدا کنسل شد ، یا اینکه به جای #C فقط در VB تعریف شده در صورتی که #C ممکن است که هم اکنون آن ویژگی هارا داشته باشد یا اصلا فرقی نداشته باشد که با آن ویژگی ها #C را شروع کنیم.
بقیهٔ ویژگی هایی که خواهیم دید ، یا برای پیاده سازی برنامه ریزی شده اند یا در ورژن بعدی #C پیاده سازی خواهند شد.تضمینی وجود ندارد که ویژگیهایی که برایش برنامه ریزی شده تا پیاده سازی شود،در زمان آمدن زبان بعدی پیاده سازی آن انجام شده باشد.حتی ممکن است به صورت کامل cancel شود.به یاد داشته باشید که تیم طراحی زبان ، مستندات خود را در زمان meeting خود در CodePlex اضافه میکنند ،بنا بر این آن دست از برنامه نویسی که مشتاق هستند در مورد ویژگی های #C اطلاعاتی به دست باورند میتوانند کار آنها را دنبال کنند.
Null Propagation
اگرچه پیاده سازی این ویژگی تقریبا به اتمام رسیده اما هنوز در extensionهای visual studio برای دانلود قابل دسترسی نیست.شخصاً معمولا اتفاق افتاده که فراموش کردم و یکی از propertyهایی که به آن نیاز داشتهام را null رد کرده ام.
در نظر بگیرید که یک کلاس person داریم ، person یک address دارد که میخواهیم نام خیابان را به آن بدهیم. آدرس به وسیلهٔ یک object نشان داده میشود و اگر شخص آدرس خود را ندهد ، property برای آدرس روی کلاس null, person میشود. ممکن است بگوئید طراحی بدی دارد ،شاید حق با شما باشد.
گیر کردن در دنیای Nullها ! ما نیاز به یک راه بهتر داریم تا بتوانیم این گونه سناریوها را handle کنیم و اینجا درست جایی است که Null Propagation وارد بازی میشود.
به کد زیر نگاه کنید.چیزهایی را که تا الان میگفتیم را نشان میدهد.
class Person { public string Name { get; set; } public Address Address { get; set; } } class Address { public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } }
حالا میتونیم یک instance از person ایجاد کنیم بدون این که به آن address بدهیم،در کد زیر میبینید:
var filip = new Person { Name = "Filip" }; Console.WriteLine(filip.Address.AddressLine1);
البته این کار باعث میشود که گرفتار null refrence excepion شویم. برای حل این مشکل باید یک خط اضافه کنیم و درون آن null را چک کنیم ،به صورت زیر:
Console.WriteLine(filip.Address == null ? "No Address" : filip.Address.AddressLine1);
با استفاده از Null Propagation ،به راحتی میتونیم یک کاراکتر را اضافه کنیم تا این مشکل حل شود، کد زیر زیباتر است:
Console.WriteLine(filip.Address?.AddressLine1 ?? "No Address");
در نتیجهٔ کد بالا، اگر یکی از Null Propagationها null را تشخیص دهد، عبارت null بر میگرداند.
Literalهای باینری و جداکنندههای ارقام
احتمالا بیشتر ما از شمارههای باینری به صورت روزانه استفاده نمیکنیم،با این حال برای کسانی که این کار را میکنند ، ویژگی ای طرح ریزی شده که بتوانند خیلی راحت تر از binary literalها در کدهایشان استفاده کنند.اگر بخواهید باینری عدد ۸ را نمایش دهید ، میتوانید به سادگی آن را این گونه تعریف کنید : ۰b۰۰۰۰۱۰۰۰ .
این راه تقریبا شبیه به راهی است که عدد را به صورت hexadecimal مینوشتیم.
صحبتی از عددهای hexadecimal : چیزی داریم تحت عنوان جداکنندههای ارقام ( digit seperators ) . آنها برای این مورد استفاده قرار میگیرند که برای چشم راحت تر هستند. عبارت hexadecimal روبرو را در نظر بگیرید : ۰xFF۰۰FAAF . برای اینکه بهتر بتوان آن را خواند ، برای آن یک جدا کننده طرح ریزی شده است. جدا کننده یک مقداری در عبارت hexadecimal تفاوت ایجاد میکند، اما خوانایی عبارت را همان طور که میبینید بسیار آسان تر میکند:
۰xFF_۰۰_FA_AF
Expression-bodied members
اگر از constructorهای اصلی استفاده کنیم،ممکن است بخواهیم در کلاسمان propertyای تعریف کنیم که هر بار چیزی را محاسبه کند.مثلا میتواند مساحت مستطیل را بر طبق طول وعرضی که به constructor اصلی مستطیل پاس داده میشود محاسبه کند، یا ممکن است چیز دیگری را بخواهیم که محاسبه کند.
Expression-bodied members به معنی این است که میتوانیم در کلاسمان memberها یا اعضایی داشته باشیم که expression body دارند. مثل همیشه هنگامی که expression و بدنه ی آن را تعریف میکنیم ، از syntax <= استفاده میکنیم.
همان طور که در مثال زیر میبینید،یک عضو public داریم که یک عبارت را معین میکند ، وقتی فراخوانی میشود مساحت مستطیل را محاسبه میکند:
class Rectangle(int width, int height) { public int Area => width * height; }
Event initializers
بسیاری از ما به صورت روزانه از eventها استفاده میکنیم،کاملا رنج آور است وقتی که قدرت initializer ها را داریم ،نتوانیم الگوی مشابهی برای آن در event داشته باشیم. این به این معنی است که ما نمیتوانیم در object initializer معمولی خودمان ،event هارا initialize کنیم.
در کدی که میبینید ،ما یک web client داریم که هنگامی که دانلود کامل شد به ما اطلاع میدهد.میتوانیم این کار را به این صورت انجام دهیم که ،از یک object initializer استفاده کنیم و event را مستقیماً در object initialization مقدار دهی کنیم.
var client = new WebClient { DownloadFileCompleted += DownloadFileCompletedHandler };
عملگر NameOf
در بعضی موارد، ممکن است بخواهید نام چیزی را در کد باز یابی کنید که عضوی از کلاس یا یک مسیر فیزیکی باشد. عملگر جدید NameOf این امکان را به ما میدهد.نتیجهٔ فراخوانی NameOf(Debug.WriteLine) ،writeline خواهد بود. خیلی خوب است که مجبور نیستیم که string هارا برای نشان دادن اسم member در کدمان قرار دهیم.
Field Targetها در auto-property ها
propertyها به طور گسترده استفاده میشوند ، با این حال تا کنون declaration برای فیلد پشتیبانی property ،بدون اینکه خودتان به طور دستی آن را تنظیم کنید غیر ممکن بوده است.
در کد زیر مثالی میبینید از اینکه چگونه field targeting میتواند کار کند:
[field: NonSerialized] public int Age { get; set; }
در این مورد باید بگوییم که field پشتیبان Age نمی تواند مرتب شود.
ویژگیهایی که ممکن است در 6.0 #C حضور داشته باشد
همانطور که گفت شد ،ویژگی هایی وجود دارد که ممکن است در ورژن بعدی زبان آورده شود یا نشود.به ویژگیاهایی که هنوز مطمئن نیستیم که چگونه پیاده سازی خواهند شد نمی پردازیم:
-عملگر semicolon
-using params with IEnumerable
-استنتاج constructor
-درج string
نتیجه گیری
اگر برای استفاده از این ویژگیها آمادگی دارید ،میتوانید ورژن CTP در visual studio ۱۴ را دانلود کنید. RTM در سال ۲۰۱۵ منتشر میشود.هم اکنون ویژگیهای زیادی پیاده سازی شده است. داشتن کامپایلری که در #C و VB نوشته شده باشد برای خاصیت های maintainability و extensibility (توسعه پذیری ) خیلی خوب است.
برای کسانی که تمایل دارند می توانند video ویژگیها ی جدید را نیز مشاهده کنند.
- C#.net
- 2k بازدید
- 19 تشکر