اشتراکها
مدتی قبل مطلبی تحت عنوان "What’s coming in the next version of ASP.NET Webforms" منتشر شد (که نویسنده آن دقیقا مشخص نیست این اطلاعات را از کجا آورده و همچنین تکذیبیهای هم جایی در مورد آن صادر نشد ...)؛ بنابراین خلاصهای از آنرا با هم مرور خواهیم کرد:
اخیرا تمام توجه تیم ASP.NET معطوف نسخهی MVC آن شده است؛ هر چند هنوز تعداد قابل توجهی از پروژههای ASP.NET بر اساس Webforms تهیه شدهاند یا میشوند. همچنین برخلاف مطالب منتشره در انجمنها یا بلاگهای مرتبط، تیم ASP.NET ، نگارش Webforms را فراموش نکرده و حتی نگارش 4 آن نیز تعدادی از قابلیتهای MVC مانند URL Routing، حجم کمتر ViewState و کنترل بیشتر بر روی HTML نهایی را به همراه داشته است.
به روز رسانیهای متوالی MVC (که اکنون به نگارش 3 رسیده است)، شاید این تصور را پیش آورده باشد که دیگر Webforms مرده است! اما مهترین دلیل به روز رسانیهای دیر هنگام نسخهی Webforms ، یکی بودن اسمبلیهای آن با مجموعهی اصلی دات نت فریم ورک است (برخلاف نسخهی MVC که به صورت افزونهای برای این مجموعه ارائه شده است).
نسخهی بعدی Webforms (حداقل) شامل تازهها و پیشرفتهای زیر خواهد بود:
MVC ModelBinders
در نسخهی MVC مفهومی به نام Model binders وجود دارد. کار آن مقدار دهی مدل برنامه به صورت خودکار بر اساس اطلاعات وارد شده توسط کاربر در رابط کاربری برنامه است. برای مثال در Webforms داریم employee.Name = txtName.Text . به این معنا که مقدر Text یک جعبهی متنی به نام txtName را به خاصیت Name شیء employee نسبت بده. اینکار (انقیاد اطلاعات رابط کاربر به مدل برنامه) با وجود Model binders در نسخهی MVC به صورت خودکار انجام میشود. این مورد دو مزیت عمده را به همراه خواهد داشت: الف) سادگی و حجم کمتر کد ب) امکان تهیه سادهتر unit test جهت قسمتهای مختلف برنامه (چون دیگر به txtName گره نخواهد خورد).
امکانات Model binders ، گفته شده (مطابق مرجع فوق!) که قرار است جزئی از نگارش بعدی Webforms باشد ... (امیدوارم!)
بهبودهای حاصل شده در اعتبار سنجی
نسخهی بعدی Webforms شامل پیشرفتهای اعتبارسنجی نسخهی MVC نیز خواهد بود. به این معنا که امکان کنارگذاشتن کنترلهای اعتبار سنجی Webforms و استفاده یکپارچه از امکانات jQuery فراهم خواهد شد (به این صورت دیگر شما محدود به یک سری کنترل از پیش تعیین شده نخواهید بود و امکان دسترسی به کوهی از افزونههای اعتبار سنجی jQuery را خواهید داشت).
CSS Sprites
CSS Sprites که در نگارش بعدی Webforms پشتیبانی خواهد شد (+)، تکنیکی است جهت کاهش تعداد رفت و برگشتهای به سرور با ارائهی یک فایل حاوی تمام تصاویر قرار گرفته شده در یک شبکه یا گرید. به این صورت بجای دها یا صدها رفت و برگشت به سرور جهت دریافت تصاویر یک صفحه، تنها یک رفت و برگشت انجام خواهد شد.
net framework. شامل Framework
Class Library یا به اختصار FCL است. FCL مجموعهای از dll اسمبلیهایی است که صدها و هزاران نوع در آن تعریف شدهاند و هر نوع تعدادی کار انجام
میدهد. همچنین مایکروسافت کتابخانههای اضافهتری را چون azure و Directx نیز ارائه کرده است که باز هر کدام شامل نوعهای زیادی میشوند. این
کتابخانه به طور شگفت آوری باعث سرعت و راحتی توسعه دهندگان در زمینه
فناوریهای مایکروسافت گشته است.
تعدادی از فناوریهایی که توسط این کتابخانه پشتیبانی میشوند در زیر آمده است:
Web Service: این فناوری اجازهی ارسال و دریافت پیامهای تحت شبکه را به خصوص بر روی اینترنت، فراهم میکند و باعث ارتباط جامعتر بین برنامهها و فناوریهای مختلف میگردد. در انواع جدیدتر WCF و Web Api نیز به بازار ارائه شدهاند.
webform و MVC : فناوریهای تحت وب که باعث سهولت در ساخت وب سایتها میشوند که وب فرم رفته رفته به سمت منسوخ شدن پیش میرود و در صورتی که قصد دارید طراحی وب را آغاز کنید توصیه میکنم از همان اول به سمت MVC بروید.
Rich Windows GUI Application : برای سهولت در ایجاد برنامههای تحت وب حالا چه با فناوری WPF یا فناوری قدیمی و البته منسوخ شده Windows Form.
Windows Console Application: برای ایجاد برنامههای ساده و بدون رابط گرافیکی.
Windows Services: شما میتوانید یک یا چند سرویس تحت ویندوز را که توسط Service Control Manager یا به اختصار SCM کنترل میشوند، تولید کنید.
Database stored Procedure: نوشتن stored procedure بر روی دیتابیسهایی چون sql server و اوراکل و ... توسط فریم ورک دات نت مهیاست.
Component Libraray: ساخت اسمبلیهای واحدی که میتوانند با انواع مختلفی از موارد بالا ارتباط برقرار کنند.
Portable Class Libary : این نوع پروژهها شما را قادر میسازد تا کلاسهایی با قابلیت انتقال پذیری برای استفاده در سیلور لایت، ویندوز فون و ایکس باکس و فروشگاه ویندوز و ... تولید کنید.
ازآنجا که یک کتابخانه شامل زیادی نوع میگردد سعی شده است گروه بندیهای مختلفی از آن در قالبی به اسم فضای نام namespace تقسیم بندی گردند که شما آشنایی با آنها دارید. به همین جهت فقط تصویر زیر را که نمایشی از فضای نامهای اساسی و مشترک و پرکاربرد هستند، قرار میدهم.
تعدادی از فناوریهایی که توسط این کتابخانه پشتیبانی میشوند در زیر آمده است:
Web Service: این فناوری اجازهی ارسال و دریافت پیامهای تحت شبکه را به خصوص بر روی اینترنت، فراهم میکند و باعث ارتباط جامعتر بین برنامهها و فناوریهای مختلف میگردد. در انواع جدیدتر WCF و Web Api نیز به بازار ارائه شدهاند.
webform و MVC : فناوریهای تحت وب که باعث سهولت در ساخت وب سایتها میشوند که وب فرم رفته رفته به سمت منسوخ شدن پیش میرود و در صورتی که قصد دارید طراحی وب را آغاز کنید توصیه میکنم از همان اول به سمت MVC بروید.
Rich Windows GUI Application : برای سهولت در ایجاد برنامههای تحت وب حالا چه با فناوری WPF یا فناوری قدیمی و البته منسوخ شده Windows Form.
Windows Console Application: برای ایجاد برنامههای ساده و بدون رابط گرافیکی.
Windows Services: شما میتوانید یک یا چند سرویس تحت ویندوز را که توسط Service Control Manager یا به اختصار SCM کنترل میشوند، تولید کنید.
Database stored Procedure: نوشتن stored procedure بر روی دیتابیسهایی چون sql server و اوراکل و ... توسط فریم ورک دات نت مهیاست.
Component Libraray: ساخت اسمبلیهای واحدی که میتوانند با انواع مختلفی از موارد بالا ارتباط برقرار کنند.
Portable Class Libary : این نوع پروژهها شما را قادر میسازد تا کلاسهایی با قابلیت انتقال پذیری برای استفاده در سیلور لایت، ویندوز فون و ایکس باکس و فروشگاه ویندوز و ... تولید کنید.
ازآنجا که یک کتابخانه شامل زیادی نوع میگردد سعی شده است گروه بندیهای مختلفی از آن در قالبی به اسم فضای نام namespace تقسیم بندی گردند که شما آشنایی با آنها دارید. به همین جهت فقط تصویر زیر را که نمایشی از فضای نامهای اساسی و مشترک و پرکاربرد هستند، قرار میدهم.
در CLR مفهومی به نام Common Type System یا CTS وجود دارد که توضیح میدهد نوعها باید چگونه تعریف شوند و چگونه باید رفتار کنند که این قوانین از آنجایی که در ریشهی CLR نهفته است، بین تمامی زبانهای دات نت مشترک میباشد. تعدادی از مشخصات این CTS در زیر آورده شده است ولی در آینده بررسی بیشتری روی آنان خواهیم داشت:
- فیلد
- متد
- پراپرتی
- رویدادها
CTS همچنین شامل قوانین زیادی در مورد وضعیت کپسوله سازی برای اعضای یک نوع دارد:
- private
- public
- Family یا در زبانهایی مثل سی ++ و سی شارپ با نام protected شناخته میشود.
- family and assembly: این هم مثل بالایی است ولی کلاس مشتق شده باید در همان اسمبلی باشد. در زبانهایی چون سی شارپ و ویژوال بیسیک، چنین امکانی پیاده سازی نشدهاست و دسترسی به آن ممکن نیست ولی در IL Assembly چنین قابلیتی وجود دارد.
- Assembly یا در بعضی زبانها به نام internal شناخته میشود.
- Family Or Assembly: که در سی شارپ با نوع Protected internal شناخته میشود. در این وضعیت هر عضوی در هر اسمبلی قابل ارث بری است و یک عضو فقط میتواند در همان اسمبلی مورد استفاده قرار بگیرد.
موارد دیگری که تحت قوانین CTS هستند مفاهیم ارث بری، متدهای مجازی، عمر اشیاء و .. است.
یکی دیگر از ویژگیهای CTS این است که همهی نوعها از نوع شیء Object که در فضای نام system قرار دارد ارث بری کردهاند. به همین دلیل همهی نوعها حداقل قابلیتهایی را که یک نوع object ارئه میدهد، دارند که به شرح زیر هستند:
- مقایسهی دو شیء از لحاظ برابری.
- به دست آوردن هش کد برای هر نمونه از یک شیء
- ارائهای از وضعیت شیء به صورت رشته ای
- دریافت نوع شیء جاری
وجود COMها به دلیل ایجاد اشیاء در یک زبان متفاوت بود تا با زبان دیگر ارتباط برقرار کنند. در طرف دیگر CLR هم بین زبانهای برنامه نویسی یکپارچگی ایجاد کرده است. یکپارچگی زبانهای برنامه نویسی علل زیادی دارند. اول اینکه رسیدن به هدف یا یک الگوریتم خاص در زبان دیگر راحتتر از زبان پایه پروژه است. دوم در یک کار تیمی که افراد مختلف با دانش متفاوتی حضور دارند و ممکن است زیان هر یک متفاوت باشند.
برای ایجاد این یکپارچگی، مایکروسافت سیستم CLS یا Common Language Specification را راه اندازی کرد. این سیستم برای تولیدکنندگان کامپایلرها جزئیاتی را تعریف میکند که کامپایلر آنها را باید با حداقل ویژگیهای تعریف شدهی CLR، پشتیبانی کند.
CLR/CTS مجموعهای از ویژگیها را شامل میشود و گفتیم که هر زبانی بسیاری از این ویژگیها را پشتیبانی میکند ولی نه کامل. به عنوان مثال برنامه نویسی که قصد کرده از IL Assembly استفاده کند، قادر است از تمامی این ویژگیهایی که CLR/CTS ارائه میدهند، استفاده کند ولی تعدادی دیگر از زبانها مثل سی شارپ و فورترن و ویژوال بیسیک تنها بخشی از آن را استفاده میکنند و CLS حداقل ویژگی که بین همه این زبانها مشترک است را ارائه میکند.
شکل زیر را نگاه کنید:
یعنی
اگر شما دارید نوع جدیدی را در یک زبان ایجاد میکنید که قصد دارید در یک
زبان دیگر استفاده شود، نباید از امتیازات ویژهای که آن زبان در اختیار شما میگذارد و به بیان بهتر CLS آنها را پشتیبانی نمیکند، استفاده کنید؛ چرا
که کد شما ممکن است در زبان دیگر مورد استفاده قرار نگیرد.
به کد زیر دقت کنید. تعدادی از کدها سازگاری کامل با CLS دارند که به آنها CLS Compliant گویند و تعدادی از آنها non-CLS-Compliant هستند یعنی با
CLS سازگاری ندارند ولی استفاده از خاصیت [(assembly: CLSCompliant(true] باعث میشود که تا کامپایلر از پشتیبانی و سازگاری این کدها اطمینان کسب کند و در صورت وجود، از اجرای آن جلوگیری کند. با کمپایل کد زیر دو اخطار به ما میرسد.
using System; // Tell compiler to check for CLS compliance [assembly: CLSCompliant(true)] namespace SomeLibrary { // Warnings appear because the class is public public sealed class SomeLibraryType { // Warning: Return type of 'SomeLibrary.SomeLibraryType.Abc()' // is not CLScompliant public UInt32 Abc() { return 0; } // Warning: Identifier 'SomeLibrary.SomeLibraryType.abc()' // differing only in case is not CLScompliant public void abc() { } // No warning: this method is private private UInt32 ABC() { return 0; } } }
اولین اخطار اینکه
یکی از متدها یک عدد صحیح بدون علامت unsigned integer را بر میگرداند که همهی زبانها آن را پشتیبانی نمیکنند و خاص بعضی از زبان هاست.
دومین اخطار اینکه دو متد یکسان وجود دارند که در حروف بزرگ و کوچک تفاوت دارند. ولی زبان هایی چون ویژوال بیسیک نمیتوانند تفاوتی بین دو متد abc و ABC بیابند.
نکتهی جالب اینکه اگر شما کلمه public را از جلوی نام کلاس بردارید تمامی این اخطارها لغو میشود. به این خاطر که اینها اشیای داخلی آن اسمبلی شناخته شده و قرار نیست از بیرون به آن دسترسی صورت بگیرد. عضو خصوصی کد بالا را ببینید؛ کامنت بالای آن میگوید که چون خصوصی است هشداری نمیگیرد، چون قرار نیست در زبان مقصد از آن به طور مستقیم استفاده کند.
برای دیدن قوانین CLS به این صفحه مراجعه فرمایید.
دومین اخطار اینکه دو متد یکسان وجود دارند که در حروف بزرگ و کوچک تفاوت دارند. ولی زبان هایی چون ویژوال بیسیک نمیتوانند تفاوتی بین دو متد abc و ABC بیابند.
نکتهی جالب اینکه اگر شما کلمه public را از جلوی نام کلاس بردارید تمامی این اخطارها لغو میشود. به این خاطر که اینها اشیای داخلی آن اسمبلی شناخته شده و قرار نیست از بیرون به آن دسترسی صورت بگیرد. عضو خصوصی کد بالا را ببینید؛ کامنت بالای آن میگوید که چون خصوصی است هشداری نمیگیرد، چون قرار نیست در زبان مقصد از آن به طور مستقیم استفاده کند.
برای دیدن قوانین CLS به این صفحه مراجعه فرمایید.
سازگاری با کدهای مدیریت نشده
در بالا در مورد یکپارچگی و سازگاری کدهای مدیریت شده توسط CLS صحبت کردیم ولی در مورد ارتباط با کدهای مدیریت نشده چطور؟
مایکروسافت موقعیکه CLR را ارئه کرد، متوجه این قضیه بود که بسیاری از شرکتها توانایی اینکه کدهای خودشون را مجددا طراحی و پیاده سازی کنند، ندارند و خوب، سورسهای مدیریت نشدهی زیادی هم موجود هست که توسعه دهندگان علاقه زیادی به استفاده از آنها دارند. در نتیجه مایکروسافت طرحی را ریخت که CLR هر دو قسمت کدهای مدیریت شده و نشده را پشتیبانی کند. دو نمونه از این پشتیبانی را در زیر بیان میکنیم:
یک. کدهای مدیریت شده میتوانند توابع مدیریت شده را در قالب یک dll صدا زده و از آنها استفاده کنند.
دو. کدهای مدیریت شده میتوانند از کامپوننتهای COM استفاده کنند: بسیاری از شرکتها از قبل بسیاری از کامپوننتهای COM را ایجاد کرده بودند که کدهای مدیریت شده با راحتی با آنها ارتباط برقرار میکنند. ولی اگر دوست دارید روی آنها کنترل بیشتری داشته باشید و آن کدها را به معادل CLR تبدیل کنید؛ میتوانید از ابزار کمکی که مایکروسافت همراه فریم ورک دات نت ارائه کرده است استفاده کنید. نام این ابزار TLBIMP.exe میباشد که از Type Library Importer گرفته شده است.
سه. اگر کدهای مدیریت نشدهی زیادتری دارید شاید راحتتر باشد که برعکس کار کنید و کدهای مدیریت شده را در در یک برنامهی مدیریت نشده اجرا کنید. این کدها میتوانند برای مثال به یک Activex یا shell Extension تبدیل شده و مورد استفاده قرار گیرند. ابزارهای TLBEXP .exe و RegAsm .exe برای این منظور به همراه فریم ورک دات نت عرضه شده اند.
سورس کد Type Library Importer را میتوانید در کدپلکس بیابید.
در ویندوز 8 به بعد مایکروسافت API جدید را تحت عنوان WinsowsRuntime یا winRT ارائه کرده است . این api یک سیستم داخلی را از طریق کامپوننتهای com ایجاد کرده و به جای استفاده از فایلهای کتابخانهای، کامپوننتها api هایشان را از طریق متادیتاهایی بر اساس استاندارد ECMA که توسط تیم دات نت طراحی شده است معرفی میکنند.
زیبایی این روش اینست که کد نوشته شده در زبانهای دات نت میتواند به طور مداوم با apiهای winrt ارتباط برقرار کند. یعنی همهی کارها توسط CLR انجام میگیرد بدون اینکه لازم باشد از ابزار اضافی استفاده کنید. در آینده در مورد winRT بیشتر صحبت میکنیم.
در بالا در مورد یکپارچگی و سازگاری کدهای مدیریت شده توسط CLS صحبت کردیم ولی در مورد ارتباط با کدهای مدیریت نشده چطور؟
مایکروسافت موقعیکه CLR را ارئه کرد، متوجه این قضیه بود که بسیاری از شرکتها توانایی اینکه کدهای خودشون را مجددا طراحی و پیاده سازی کنند، ندارند و خوب، سورسهای مدیریت نشدهی زیادی هم موجود هست که توسعه دهندگان علاقه زیادی به استفاده از آنها دارند. در نتیجه مایکروسافت طرحی را ریخت که CLR هر دو قسمت کدهای مدیریت شده و نشده را پشتیبانی کند. دو نمونه از این پشتیبانی را در زیر بیان میکنیم:
یک. کدهای مدیریت شده میتوانند توابع مدیریت شده را در قالب یک dll صدا زده و از آنها استفاده کنند.
دو. کدهای مدیریت شده میتوانند از کامپوننتهای COM استفاده کنند: بسیاری از شرکتها از قبل بسیاری از کامپوننتهای COM را ایجاد کرده بودند که کدهای مدیریت شده با راحتی با آنها ارتباط برقرار میکنند. ولی اگر دوست دارید روی آنها کنترل بیشتری داشته باشید و آن کدها را به معادل CLR تبدیل کنید؛ میتوانید از ابزار کمکی که مایکروسافت همراه فریم ورک دات نت ارائه کرده است استفاده کنید. نام این ابزار TLBIMP.exe میباشد که از Type Library Importer گرفته شده است.
سه. اگر کدهای مدیریت نشدهی زیادتری دارید شاید راحتتر باشد که برعکس کار کنید و کدهای مدیریت شده را در در یک برنامهی مدیریت نشده اجرا کنید. این کدها میتوانند برای مثال به یک Activex یا shell Extension تبدیل شده و مورد استفاده قرار گیرند. ابزارهای TLBEXP .exe و RegAsm .exe برای این منظور به همراه فریم ورک دات نت عرضه شده اند.
سورس کد Type Library Importer را میتوانید در کدپلکس بیابید.
در ویندوز 8 به بعد مایکروسافت API جدید را تحت عنوان WinsowsRuntime یا winRT ارائه کرده است . این api یک سیستم داخلی را از طریق کامپوننتهای com ایجاد کرده و به جای استفاده از فایلهای کتابخانهای، کامپوننتها api هایشان را از طریق متادیتاهایی بر اساس استاندارد ECMA که توسط تیم دات نت طراحی شده است معرفی میکنند.
زیبایی این روش اینست که کد نوشته شده در زبانهای دات نت میتواند به طور مداوم با apiهای winrt ارتباط برقرار کند. یعنی همهی کارها توسط CLR انجام میگیرد بدون اینکه لازم باشد از ابزار اضافی استفاده کنید. در آینده در مورد winRT بیشتر صحبت میکنیم.
سخن پایانی: ممنون از دوستان عزیز بابت پیگیری مطالب تا بدینجا. تا این قسمت فصل اول کتاب با عنوان اصول اولیه CLR بخش اول مدل اجرای CLR به پایان رسید.
ادامهی مطالب بعد از تکمیل هر بخش در دسترس دوستان قرار خواهد گرفت.
زمانیکه یک متد async، یک Task یا Task of T (نسخهی جنریک Task) را باز میگرداند، کامپایلر سیشارپ به صورت خودکار تمام استثناءهای رخ داده درون متد را دریافت کرده و از آن برای تغییر حالت Task به اصطلاحا faulted state استفاده میکند. همچنین زمانیکه از واژهی کلیدی await استفاده میشود، کدهایی که توسط کامپایلر تولید میشوند، عملا مباحث Continue موجود در TPL یا Task parallel library معرفی شده در دات نت 4 را پیاده سازی میکنند و نهایتا نتیجهی Task را در صورت وجود، دریافت میکند. زمانیکه نتیجهی یک Task مورد استفاده قرار میگیرد، اگر استثنایی وجود داشته باشد، مجددا صادر خواهد شد. برای مثال اگر خروجی یک متد async از نوع Task of T باشد، امکان استفاده از خاصیتی به نام Result نیز برای دسترسی به نتیجهی آن وجود دارد:
در این مثال یکی از روشهای استفاده از متدهای async را در یک برنامهی کنسول مشاهده میکنید. هر چند خروجی متد doSomethingAsync از نوع Task of int است، اما مستقیما یک int بازگشت داده شده است. تبدیلات نهایی در اینجا توسط کامپایلر انجام میشود. همچنین نحوهی استفاده از خاصیت Result را نیز در متد Main مشاهده میکنید.
البته باید دقت داشت، زمانیکه از خاصیت Result استفاده میشود، این متد همزمان عمل خواهد کرد و نه غیرهمزمان (ترد جاری را بلاک میکند؛ یکی از موارد مجاز استفاده از آن در متد Main برنامههای کنسول است). همچنین اگر در متد doSomethingAsync استثنایی رخ داده باشد، این استثناء زمان استفاده از Result، به صورت یک AggregateException مجددا صادر خواهد شد. وجود کلمهی Aggregate در اینجا به علت امکان استفادهی تجمعی و ترکیب چندین Task باهم و داشتن چندین شکست و استثنای ممکن است.
همچنین اگر از کلمهی کلیدی await بر روی یک faulted task استفاده کنیم، AggregateException صادر نمیشود. در این حالت کامپایلر AggregateException را بررسی کرده و آنرا تبدیل به یک Exception متداول و معمول کدهای دات نت میکند. به عبارتی سعی شدهاست در این حالت، رفتار کدهای async را شبیه به رفتار کدهای متداول همزمان شبیه سازی کنند.
یک مثال
در اینجا توسط متد getTitleAsync، اطلاعات یک صفحهی وب به صورت async دریافت شده و سپس عنوان آن استخراج میشود. در متد showTitlesAsync نیز از آن استفاده شده و در طی یک حلقه، چندین وب سایت مورد بررسی قرار خواهند گرفت. چون متد getTitleAsync از نوع async تعریف شدهاست، فراخوان آن نیز باید async تعریف شود تا بتوان از واژهی کلیدی await برای کار با آن استفاده کرد.
نهایتا در متد Main برنامه، وظیفهی غیرهمزمان showTitlesAsync اجرا شده و تا پایان عملیات آن صبر میشود. چون خروجی آن از نوع Task است و نه Task of T، در اینجا دیگر خاصیت Result قابل دسترسی نیست. متد Wait نیز ترد جاری را همانند خاصیت Result بلاک میکند.
کلیه عملیات مبتنی برشبکه، همیشه مستعد به بروز خطا هستند. قطعی ارتباط یا حتی کندی آن میتوانند سبب بروز استثناء شوند.
برنامه را در حالت عدم اتصال به اینترنت اجرا کنید. استثنای صادر شده، در متد task.Wait ظاهر میشود (چون متدهای async ترد جاری را خالی کردهاند):
و اگر در اینجا بر روی لینک View details کلیک کنیم، در inner exception حاصل، خطای واقعی قابل مشاهده است:
همانطور که ملاحظه میکنید، استثنای صادر شده از نوع System.AggregateException است. به این معنا که میتواند حاوی چندین استثناء باشد که در اینجا تعداد آنها با عدد یک مشخص شدهاست. بنابراین در این حالات، بررسی inner exception را فراموش نکنید.
در ادامه داخل حلقهی foreach متد showTitlesAsync، یک try/catch قرار میدهیم:
اینبار اگر برنامه را اجرا کنیم، خروجی ذیل را در صفحه میتوان مشاهده کرد:
در اینجا دیگر خبری از AggregateException نبوده و استثنای واقعی رخ داده در متد await شده بازگشت داده شدهاست. کار واژهی کلیدی await در اینجا، بررسی استثنای رخ داده در متد async فراخوانی شده و بازگشت آن به جریان متداول متد جاری است؛ تا نتیجهی عملیات همانند یک کد کامل همزمان به نظر برسد. به این ترتیب کامپایلر توانسته است رفتار بروز استثناءها را در کدهای همزمان و غیرهمزمان یک دست کند. دقیقا مانند حالتی که یک متد معمولی در این بین فراخوانی شده و استثنایی در آن رخ دادهاست.
مدیریت تمام inner exceptionهای رخ داده در پردازشهای موازی
همانطور که عنوان شد، await تنها یک استثنای حاصل از Task در حال اجرا را به کد فراخوان بازگشت میدهد. در این حالت اگر این Task، چندین شکست را گزارش دهد، چطور باید برای دریافت تمام آنها اقدام کرد؟ برای مثال استفاده از Task.WhenAll میتواند شامل چندین استثنای حاصل از چندین Task باشد، ولی await تنها اولین استثنای دریافتی را بازگشت میدهد. اما اگر از خاصیتی مانند Result یا متد Wait استفاده شود، یک AggregateException حاصل تمام استثناءها را دریافت خواهیم کرد. بنابراین هرچند await تنها اولین استثنای دریافتی را بازگشت میدهد، اما میتوان به Taskهای مرتبط مراجعه کرد و سپس بررسی نمود که آیا استثناهای دیگری نیز وجود دارند یا خیر؟
برای نمونه در مثال فوق، حلقهی foreach تشکیل شده آنچنان بهینه نیست. از این جهت که هر بار تنها یک سایت را بررسی میکند، بجای اینکه مانند مرورگرها چندین ترد را به یک یا چند سایت باز کرده و نتایج را دریافت کند.
البته انجام کارها به صورت موازی همیشه ایدهی خوبی نیست ولی حداقل در این حالت خاص که با یک یا چند سرور راه دور کار میکنیم، درخواستهای همزمان دریافت اطلاعات، سبب کارآیی بهتر برنامه و بالا رفتن سرعت اجرای آن میشوند. اما مثلا در حالتیکه با سخت دیسک سیستم کار میکنیم، اجرای موازی کارها نه تنها کمکی نخواهد کرد، بلکه سبب خواهد شد تا مدام drive head در مکانهای مختلفی مشغول به حرکت شده و در نتیجه کارآیی آن کاهش یابد.
برای ترکیب چندین Task، ویژگی خاصی به زبان سیشارپ اضافه نشده، زیرا نیازی نبوده است. برای این حالت تنها کافی است از متد Task.WhenAll، برای ساخت یک Task مرکب استفاده کرد. سپس میتوان واژهی کلیدی await را بر روی این Task مرکب فراخوانی کرد.
همچنین میتوان از متد ContinueWith یک Task مرکب نیز برای جلوگیری از بازگشت صرفا اولین استثنای رخ داده توسط کامپایلر، استفاده کرد. در این حالت امکان دسترسی به خاصیت Result آن به سادگی میسر میشود که حاوی AggregateException کاملی است.
اعتبارسنجی آرگومانهای ارسالی به یک متد async
زمان اعتبارسنجی آرگومانهای ارسالی به متدهای async مهم است. بعضی از مقادیر را نمیتوان بلافاصله اعتبارسنجی کرد؛ مانند مقادیری که نباید نال باشند. تعدادی دیگر نیز پس از انجام یک Task زمانبر مشخص میشوند که معتبر بودهاند یا خیر. همچنین فراخوانهای این متدها انتظار دارند که متدهای async بلافاصله بازگشت داده شده و ترد جاری را خالی کنند. بنابراین اعتبارسنجیهای آنها باید با تاخیر انجام شود. در این حالات، دو نوع استثنای آنی و به تاخیر افتاده را شاهد خواهیم بود. استثنای آنی زمان شروع به کار متد صادر میشود و استثنای به تاخیر افتاده در حین دریافت نتایج از آن دریافت میگردد. باید دقت داشت کلیه استثناهای صادر شده در بدنهی یک متد async، توسط کامپایلر به عنوان یک استثنای به تاخیر افتاده گزارش داده میشود. بنابراین اعتبارسنجیهای آرگومانها را بهتر است در یک متد سطح بالای غیر async انجام داد تا بلافاصله بتوان استثناءهای حاصل را دریافت نمود.
از دست دادن استثناءها
فرض کنید مانند مثال قسمت قبل، دو وظیفهی async آغاز شده و نتیجهی آنها پس از await هر یک، با هم جمع زده میشوند. در این حالت اگر کل عملیات را داخل یک قطعه کد try/catch قرار دهیم، اولین await ایی که یک استثناء را صادر کند، صرفنظر از وضعیت await دوم، سبب اجرای بدنهی catch میشود. همچنین انجام این عملیات بدین شکل بهینه نیست. زیرا ابتدا باید صبر کرد تا اولین Task تمام شود و سپس دومین Task شروع گردد و به این ترتیب پردازش موازی Taskها را از دست خواهیم داد. در یک چنین حالتی بهتر است از متد await Task.WhenAll استفاده شود. در اینجا دو Task مورد نیاز، تبدیل به یک Task مرکب میشوند. این Task مرکب تنها زمانی خاتمه مییابد که هر دوی Task اضافه شده به آن، خاتمه یافته باشند. به این ترتیب علاوه بر اجرای موازی Taskها، امکان دریافت استثناءهای هر کدام را نیز به صورت تجمعی خواهیم داشت.
مشکل! همانطور که پیشتر نیز عنوان شد، استفاده از await در اینجا سبب میشود تا کامپایلر تنها اولین استثنای دریافتی را بازگشت دهد و نه یک AggregateException نهایی را. روش حل آنرا نیز عنوان کردیم. در این حالت بهتر است از متد ContinueWith و سپس استفاده از خاصیت Result آن برای دریافت کلیه استثناءها کمک گرفت.
حالت دوم از دست دادن استثناءها زمانیاست که یک متد async void را ایجاد میکنید. در این حالات بهتر است از یک Task بجای بازگشت void استفاده شود. تنها علت وجودی async voidها، استفاده از آنها در روالهای رویدادگردان UI است (در سایر حالات code smell درنظر گرفته میشود).
در مثال فوق، نحوهی ترکیب دو Task را توسط Task.WhenAll جهت اجرای موازی و سپس اعمال نکتهی یک ContinueWith خالی و در ادامه استفاده از Result نهایی را جهت دریافت تمامی استثناءهای حاصل، مشاهده میکنید.
در این مثال دیگر مانند مثال قسمت قبل
هر بار صبر نشدهاست تا یک Task تمام شود و سپس Task بعدی شروع گردد.
با کمک متد Task.WhenAll ترکیب آنها ایجاد و سپس با فراخوانی await، سبب اجرای موازی چندین Task با هم شدهایم.
مدیریت خطاهای مدیریت نشده
ابتدا مثال زیر را در نظر بگیرید:
در این مثال دو متد که یکی async Task و دیگری async void است، تعریف شدهاند.
اگر برنامه را کامپایل کنید، کامپایلر بر روی سطر فراخوانی متد Test اخطار زیر را صادر میکند. البته برنامه بدون مشکل کامپایل خواهد شد.
اما چنین اخطاری در مورد async void صادر نمیشود. بنابراین ممکن است جایی در کدها، فراخوانی await فراموش شود. اگر خروجی متد شما ازنوع Task و مشتقات آن باشد، کامپایلر حتما اخطاری را جهت رفع آن گوشزد خواهد کرد؛ اما نه در مورد متدهای void که صرفا جهت کاربردهای UI و روالهای رخدادگردان آن طراحی شدهاند.
همچنین اگر برنامه را اجرا کنید استثنای صادر شده در متد async void سبب کرش برنامه میشود؛ اما نه استثنای صادر شده در متد async Task. متدهای async void چون دارای Synchronization Context نیستند، استثنای صادره را به Thread pool برنامه صادر میکنند. به همین جهت در همان لحظه نیز سبب کرش برنامه خواهند شد. اما در حالت async Task به این نوع استثناءها اصطلاحا Unobserved Task Exception گفته شده و سبب بروز faulted state در Task تعریف شده میگردند.
برای مدیریت آنها در سطح برنامه باید در ابتدای کار و در متد Main، توسط TaskScheduler.UnobservedTaskException روال رخدادگردانی را برای مدیریت اینگونه استثناءها تدارک دید. زمانیکه GC شروع به آزاد سازی منابع میکند، این استثناءها نیز درنظر گرفته شده و سبب کرش برنامه خواهند شد. با استفاده از متد SetObserved همانند قطعه کد زیر، میتوان از کرش برنامه جلوگیری کرد:
البته لازم به ذکر است که این رفتار در دات نت 4.5 به این شکل تغییر کرده است تا کار با متدهای async سادهتر شود. در دات نت 4، یک چنین استثناءهای مدیریت نشدهای،بلافاصله سبب بروز استثناء و کرش برنامه میشدند.
به عبارتی رفتار قطعه کد زیر در دات نت 4 و 4.5 متفاوت است:
در دات نت 4 اگر این برنامه را خارج از VS.NET اجرا کنیم، برنامه کرش میکند؛ اما در دات نت 4.5 خیر و آنها به UnobservedTaskException یاد شده هدایت خواهند شد. اگر میخواهید این رفتار را به همان حالت دات نت 4 تغییر دهید، تنظیم زیر را به فایل config برنامه اضافه کنید:
یک نکتهی تکمیلی: ممکن است عبارات lambda مورد استفاده، از نوع async void باشد.
همانطور که عنوان شد باید از async void منهای مواردی که کار مدیریت رویدادهای عناصر UI را انجام میدهند (مانند برنامههای ویندوز 8)، اجتناب کرد. چون پایان کار آنها را نمیتوان تشخیص داد و همچنین کامپایلر نیز اخطاری را در مورد استفاده ناصحیح از آنها بدون await تولید نمیکند (چون نوع void اصطلاحا awaitable نیست). به علاوه بروز استثناء در آنها، بلافاصله سبب خاتمه برنامه میشود. بنابراین اگر جایی در برنامه متد async void وجود دارد، قرار دادن try/catch داخل بدنهی آن ضروری است.
در این مثال خاص ویندوز 8، شاید به نظر برسد که try/catch تعریف شده سبب مهار استثنای صادر شده میشود؛ اما خیر!
امضای متد TappedEventHandler از نوع delegate void است. بنابراین try/catch را باید داخل بدنهی روال رویدادگردان تعریف شده قرار داد و نه خارج از آن.
using System.Threading.Tasks; namespace Async05 { class Program { static void Main(string[] args) { var res = doSomethingAsync().Result; } static async Task<int> doSomethingAsync() { await Task.Delay(1); return 1; } } }
البته باید دقت داشت، زمانیکه از خاصیت Result استفاده میشود، این متد همزمان عمل خواهد کرد و نه غیرهمزمان (ترد جاری را بلاک میکند؛ یکی از موارد مجاز استفاده از آن در متد Main برنامههای کنسول است). همچنین اگر در متد doSomethingAsync استثنایی رخ داده باشد، این استثناء زمان استفاده از Result، به صورت یک AggregateException مجددا صادر خواهد شد. وجود کلمهی Aggregate در اینجا به علت امکان استفادهی تجمعی و ترکیب چندین Task باهم و داشتن چندین شکست و استثنای ممکن است.
همچنین اگر از کلمهی کلیدی await بر روی یک faulted task استفاده کنیم، AggregateException صادر نمیشود. در این حالت کامپایلر AggregateException را بررسی کرده و آنرا تبدیل به یک Exception متداول و معمول کدهای دات نت میکند. به عبارتی سعی شدهاست در این حالت، رفتار کدهای async را شبیه به رفتار کدهای متداول همزمان شبیه سازی کنند.
یک مثال
در اینجا توسط متد getTitleAsync، اطلاعات یک صفحهی وب به صورت async دریافت شده و سپس عنوان آن استخراج میشود. در متد showTitlesAsync نیز از آن استفاده شده و در طی یک حلقه، چندین وب سایت مورد بررسی قرار خواهند گرفت. چون متد getTitleAsync از نوع async تعریف شدهاست، فراخوان آن نیز باید async تعریف شود تا بتوان از واژهی کلیدی await برای کار با آن استفاده کرد.
نهایتا در متد Main برنامه، وظیفهی غیرهمزمان showTitlesAsync اجرا شده و تا پایان عملیات آن صبر میشود. چون خروجی آن از نوع Task است و نه Task of T، در اینجا دیگر خاصیت Result قابل دسترسی نیست. متد Wait نیز ترد جاری را همانند خاصیت Result بلاک میکند.
using System; using System.Collections.Generic; using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Async05 { class Program { static void Main(string[] args) { var task = showTitlesAsync(new[] { "http://www.google.com", "https://www.dntips.ir" }); task.Wait(); Console.WriteLine(); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } static async Task showTitlesAsync(IEnumerable<string> urls) { foreach (var url in urls) { var title = await getTitleAsync(url); Console.WriteLine(title); } } static async Task<string> getTitleAsync(string url) { var data = await new WebClient().DownloadStringTaskAsync(url); return getTitle(data); } private static string getTitle(string data) { const string patternTitle = @"(?s)<title>(.+?)</title>"; var regex = new Regex(patternTitle); var mc = regex.Match(data); return mc.Groups.Count == 2 ? mc.Groups[1].Value.Trim() : string.Empty; } } }
برنامه را در حالت عدم اتصال به اینترنت اجرا کنید. استثنای صادر شده، در متد task.Wait ظاهر میشود (چون متدهای async ترد جاری را خالی کردهاند):
و اگر در اینجا بر روی لینک View details کلیک کنیم، در inner exception حاصل، خطای واقعی قابل مشاهده است:
همانطور که ملاحظه میکنید، استثنای صادر شده از نوع System.AggregateException است. به این معنا که میتواند حاوی چندین استثناء باشد که در اینجا تعداد آنها با عدد یک مشخص شدهاست. بنابراین در این حالات، بررسی inner exception را فراموش نکنید.
در ادامه داخل حلقهی foreach متد showTitlesAsync، یک try/catch قرار میدهیم:
static async Task showTitlesAsync(IEnumerable<string> urls) { foreach (var url in urls) { try { var title = await getTitleAsync(url); Console.WriteLine(title); } catch (Exception ex) { Console.WriteLine(ex); } } }
System.Net.WebException: The remote server returned an error: (502) Bad Gateway. System.Net.WebException: The remote server returned an error: (502) Bad Gateway. Press any key to exit...
مدیریت تمام inner exceptionهای رخ داده در پردازشهای موازی
همانطور که عنوان شد، await تنها یک استثنای حاصل از Task در حال اجرا را به کد فراخوان بازگشت میدهد. در این حالت اگر این Task، چندین شکست را گزارش دهد، چطور باید برای دریافت تمام آنها اقدام کرد؟ برای مثال استفاده از Task.WhenAll میتواند شامل چندین استثنای حاصل از چندین Task باشد، ولی await تنها اولین استثنای دریافتی را بازگشت میدهد. اما اگر از خاصیتی مانند Result یا متد Wait استفاده شود، یک AggregateException حاصل تمام استثناءها را دریافت خواهیم کرد. بنابراین هرچند await تنها اولین استثنای دریافتی را بازگشت میدهد، اما میتوان به Taskهای مرتبط مراجعه کرد و سپس بررسی نمود که آیا استثناهای دیگری نیز وجود دارند یا خیر؟
برای نمونه در مثال فوق، حلقهی foreach تشکیل شده آنچنان بهینه نیست. از این جهت که هر بار تنها یک سایت را بررسی میکند، بجای اینکه مانند مرورگرها چندین ترد را به یک یا چند سایت باز کرده و نتایج را دریافت کند.
البته انجام کارها به صورت موازی همیشه ایدهی خوبی نیست ولی حداقل در این حالت خاص که با یک یا چند سرور راه دور کار میکنیم، درخواستهای همزمان دریافت اطلاعات، سبب کارآیی بهتر برنامه و بالا رفتن سرعت اجرای آن میشوند. اما مثلا در حالتیکه با سخت دیسک سیستم کار میکنیم، اجرای موازی کارها نه تنها کمکی نخواهد کرد، بلکه سبب خواهد شد تا مدام drive head در مکانهای مختلفی مشغول به حرکت شده و در نتیجه کارآیی آن کاهش یابد.
برای ترکیب چندین Task، ویژگی خاصی به زبان سیشارپ اضافه نشده، زیرا نیازی نبوده است. برای این حالت تنها کافی است از متد Task.WhenAll، برای ساخت یک Task مرکب استفاده کرد. سپس میتوان واژهی کلیدی await را بر روی این Task مرکب فراخوانی کرد.
همچنین میتوان از متد ContinueWith یک Task مرکب نیز برای جلوگیری از بازگشت صرفا اولین استثنای رخ داده توسط کامپایلر، استفاده کرد. در این حالت امکان دسترسی به خاصیت Result آن به سادگی میسر میشود که حاوی AggregateException کاملی است.
اعتبارسنجی آرگومانهای ارسالی به یک متد async
زمان اعتبارسنجی آرگومانهای ارسالی به متدهای async مهم است. بعضی از مقادیر را نمیتوان بلافاصله اعتبارسنجی کرد؛ مانند مقادیری که نباید نال باشند. تعدادی دیگر نیز پس از انجام یک Task زمانبر مشخص میشوند که معتبر بودهاند یا خیر. همچنین فراخوانهای این متدها انتظار دارند که متدهای async بلافاصله بازگشت داده شده و ترد جاری را خالی کنند. بنابراین اعتبارسنجیهای آنها باید با تاخیر انجام شود. در این حالات، دو نوع استثنای آنی و به تاخیر افتاده را شاهد خواهیم بود. استثنای آنی زمان شروع به کار متد صادر میشود و استثنای به تاخیر افتاده در حین دریافت نتایج از آن دریافت میگردد. باید دقت داشت کلیه استثناهای صادر شده در بدنهی یک متد async، توسط کامپایلر به عنوان یک استثنای به تاخیر افتاده گزارش داده میشود. بنابراین اعتبارسنجیهای آرگومانها را بهتر است در یک متد سطح بالای غیر async انجام داد تا بلافاصله بتوان استثناءهای حاصل را دریافت نمود.
از دست دادن استثناءها
فرض کنید مانند مثال قسمت قبل، دو وظیفهی async آغاز شده و نتیجهی آنها پس از await هر یک، با هم جمع زده میشوند. در این حالت اگر کل عملیات را داخل یک قطعه کد try/catch قرار دهیم، اولین await ایی که یک استثناء را صادر کند، صرفنظر از وضعیت await دوم، سبب اجرای بدنهی catch میشود. همچنین انجام این عملیات بدین شکل بهینه نیست. زیرا ابتدا باید صبر کرد تا اولین Task تمام شود و سپس دومین Task شروع گردد و به این ترتیب پردازش موازی Taskها را از دست خواهیم داد. در یک چنین حالتی بهتر است از متد await Task.WhenAll استفاده شود. در اینجا دو Task مورد نیاز، تبدیل به یک Task مرکب میشوند. این Task مرکب تنها زمانی خاتمه مییابد که هر دوی Task اضافه شده به آن، خاتمه یافته باشند. به این ترتیب علاوه بر اجرای موازی Taskها، امکان دریافت استثناءهای هر کدام را نیز به صورت تجمعی خواهیم داشت.
مشکل! همانطور که پیشتر نیز عنوان شد، استفاده از await در اینجا سبب میشود تا کامپایلر تنها اولین استثنای دریافتی را بازگشت دهد و نه یک AggregateException نهایی را. روش حل آنرا نیز عنوان کردیم. در این حالت بهتر است از متد ContinueWith و سپس استفاده از خاصیت Result آن برای دریافت کلیه استثناءها کمک گرفت.
حالت دوم از دست دادن استثناءها زمانیاست که یک متد async void را ایجاد میکنید. در این حالات بهتر است از یک Task بجای بازگشت void استفاده شود. تنها علت وجودی async voidها، استفاده از آنها در روالهای رویدادگردان UI است (در سایر حالات code smell درنظر گرفته میشود).
public async Task<double> GetSum2Async() { try { var task1 = GetNumberAsync(); var task2 = GetNumberAsync(); var compositeTask = Task.WhenAll(task1, task2); await compositeTask.ContinueWith(x => { }); return compositeTask.Result[0] + compositeTask.Result[1]; } catch (Exception ex) { //todo: log ex throw; } }
در این مثال دیگر مانند مثال قسمت قبل
public async Task<double> GetSumAsync() { var leftOperand = await GetNumberAsync(); var rightOperand = await GetNumberAsync(); return leftOperand + rightOperand; }
با کمک متد Task.WhenAll ترکیب آنها ایجاد و سپس با فراخوانی await، سبب اجرای موازی چندین Task با هم شدهایم.
مدیریت خطاهای مدیریت نشده
ابتدا مثال زیر را در نظر بگیرید:
using System; using System.Threading.Tasks; namespace Async01 { class Program { static void Main(string[] args) { Test2(); Test(); Console.ReadLine(); GC.Collect(); GC.WaitForPendingFinalizers(); Console.ReadLine(); } public static async Task Test() { throw new Exception(); } public static async void Test2() { throw new Exception(); } } }
اگر برنامه را کامپایل کنید، کامپایلر بر روی سطر فراخوانی متد Test اخطار زیر را صادر میکند. البته برنامه بدون مشکل کامپایل خواهد شد.
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
همچنین اگر برنامه را اجرا کنید استثنای صادر شده در متد async void سبب کرش برنامه میشود؛ اما نه استثنای صادر شده در متد async Task. متدهای async void چون دارای Synchronization Context نیستند، استثنای صادره را به Thread pool برنامه صادر میکنند. به همین جهت در همان لحظه نیز سبب کرش برنامه خواهند شد. اما در حالت async Task به این نوع استثناءها اصطلاحا Unobserved Task Exception گفته شده و سبب بروز faulted state در Task تعریف شده میگردند.
برای مدیریت آنها در سطح برنامه باید در ابتدای کار و در متد Main، توسط TaskScheduler.UnobservedTaskException روال رخدادگردانی را برای مدیریت اینگونه استثناءها تدارک دید. زمانیکه GC شروع به آزاد سازی منابع میکند، این استثناءها نیز درنظر گرفته شده و سبب کرش برنامه خواهند شد. با استفاده از متد SetObserved همانند قطعه کد زیر، میتوان از کرش برنامه جلوگیری کرد:
using System; using System.Threading.Tasks; namespace Async01 { class Program { static void Main(string[] args) { TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; //Test2(); Test(); Console.ReadLine(); GC.Collect(); GC.WaitForPendingFinalizers(); Console.ReadLine(); } private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { e.SetObserved(); Console.WriteLine(e.Exception); } public static async Task Test() { throw new Exception(); } public static async void Test2() { throw new Exception(); } } }
به عبارتی رفتار قطعه کد زیر در دات نت 4 و 4.5 متفاوت است:
Task.Factory.StartNew(() => { throw new Exception(); }); Thread.Sleep(100); GC.Collect(); GC.WaitForPendingFinalizers();
<configuration> <runtime> <ThrowUnobservedTaskExceptions enabled="true"/> </runtime> </configuration>
یک نکتهی تکمیلی: ممکن است عبارات lambda مورد استفاده، از نوع async void باشد.
همانطور که عنوان شد باید از async void منهای مواردی که کار مدیریت رویدادهای عناصر UI را انجام میدهند (مانند برنامههای ویندوز 8)، اجتناب کرد. چون پایان کار آنها را نمیتوان تشخیص داد و همچنین کامپایلر نیز اخطاری را در مورد استفاده ناصحیح از آنها بدون await تولید نمیکند (چون نوع void اصطلاحا awaitable نیست). به علاوه بروز استثناء در آنها، بلافاصله سبب خاتمه برنامه میشود. بنابراین اگر جایی در برنامه متد async void وجود دارد، قرار دادن try/catch داخل بدنهی آن ضروری است.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState) { try { ClickMeButton.Tapped += async (sender, args) => { throw new Exception(); }; } catch (Exception ex) { // This won’t catch exceptions! TextBlock1.Text = ex.Message; } }
public delegate void TappedEventHandler(object sender, TappedRoutedEventArgs e);
بازخوردهای دوره
معرفی پروژه NotifyPropertyWeaver
- فید NuGet در VS.NET به Https تنظیم شده است. اگر دسترسی به Https
برای شما به کندی صورت میگیرد فقط کافی است مسیر فید آنرا در منوی Tools،
گزینهی Options، ذیل قسمت Package manager یافته و به
http://nuget.org/api/v2 تغییر دهید؛ یعنی به Http خالی، بجای Https؛ تا سرعت دریافت بستههای NuGet مورد نظر افزایش یابند.
- این بسته از طریق آدرس ذیل نیز قابل دریافت است:
https://az320820.vo.msecnd.net/packages/propertychanged.fody.1.42.0.nupkg
همین آدرس را در IE وارد کنید. اگر کار نکرد احتمالا تنظیمات IE شما به هم ریخته است؛ چون تنظیمات آن به صورت مستقیم روی تنظیمات اتصالی برنامههای دات نت تاثیر دارند.
- این بسته از طریق آدرس ذیل نیز قابل دریافت است:
https://az320820.vo.msecnd.net/packages/propertychanged.fody.1.42.0.nupkg
همین آدرس را در IE وارد کنید. اگر کار نکرد احتمالا تنظیمات IE شما به هم ریخته است؛ چون تنظیمات آن به صورت مستقیم روی تنظیمات اتصالی برنامههای دات نت تاثیر دارند.
- وهله شیء تولیدی شما از نوع object است. آنرا به لیست اضافه کنید و استفاده نمائید.
+ نوع جنریک در دات نت پویا نیست و نمیشود آن را به صورت یک متغیر تعریف کرد. مثلا حالت زیر مجاز نیست:
علت هم این است که هدف از نوع جنریک، compile time safety است و زمانیکه نوع در زمان کامپایل مشخص نباشد، این مساله قابل حصول نخواهد بود.
تنها حالت پویای آن استفاده از نوع object است.
- البته میشود با استفاده Reflection نوع جنریک را به صورت متغیر تعریف کنید.
+ نوع جنریک در دات نت پویا نیست و نمیشود آن را به صورت یک متغیر تعریف کرد. مثلا حالت زیر مجاز نیست:
var myType = typeof(something); List<myType> list = new List<myType>();
- البته میشود با استفاده Reflection نوع جنریک را به صورت متغیر تعریف کنید.
نظرات اشتراکها
مقایسهای بین امکانات Rider و Visual Studio
داخل متن اشاره شده که Visual Studio 22 برای مقایسه انتخاب شده اما اون ویژگی هایی که نوشته فکر نکنم ارتباطی با نسخه جدید داشته باشه. نویسنده سابقه 25 سال کار با دات نت داره ولی مقایسه منصفانه نبود مخصوصا اینکه همه ویژگیها رو گفته آخر متن اشاره میکنه Rider پولیه. البته تاکید داره Visual Studio خیلی گرون تره اما نمیگه کدوم نسخش. بهتر بودن Debug رو برای Rider گفته اما نگفته Debug برای External Libraries تو اکثر مواقع هیچ توجیهی نداره و فقط کار رو سختتر میکنه. واقعا تعصب روی یک IDE خاص رو درک نمیکنم!
نظرات اشتراکها
NET Framework 4.7. منتشر شد
دریافت نگارش آفلاین دات نت 4.7
NDP47-KB3186497-x86-x64-AllOS-ENU.exe (مخصوص سرورها و کلاینتها)
NDP47-DevPack-KB3186612-ENU.exe (مخصوص توسعه دهندهها جهت یکپارچگی با ویژوال استودیو)
برای نصب آن بر روی ویندوزهای 7، 2008 و 2012 نیاز به نصب وابستگی ذیل هم هست:
NDP47-KB3186497-x86-x64-AllOS-ENU.exe (مخصوص سرورها و کلاینتها)
NDP47-DevPack-KB3186612-ENU.exe (مخصوص توسعه دهندهها جهت یکپارچگی با ویژوال استودیو)
برای نصب آن بر روی ویندوزهای 7، 2008 و 2012 نیاز به نصب وابستگی ذیل هم هست:
نظرات اشتراکها
امکانات جدید سی شارپ 6
به طور خلاصه در این ویدیو به موارد زیر پرداخته میشود:
1- صدا زدن متدهای کلاس ایستا بدون به کار بردن نام کلاس
2- ایجاد توابع یا متدهای تک خطی
3- شیوه ای مدرن از به کاربر بردن string formatter
4- آماده سازی اشیا در وهله ساخت اینبار ایندکسرها
5- مروری بر متن باز شدن هسته دات نت و مشتقات آن و ایجاد زبان برنامه نویسی مختص خودتان
6- مروری بر XAML
و...
ویدیوی بسیار جالبی بود
1- صدا زدن متدهای کلاس ایستا بدون به کار بردن نام کلاس
2- ایجاد توابع یا متدهای تک خطی
3- شیوه ای مدرن از به کاربر بردن string formatter
4- آماده سازی اشیا در وهله ساخت اینبار ایندکسرها
5- مروری بر متن باز شدن هسته دات نت و مشتقات آن و ایجاد زبان برنامه نویسی مختص خودتان
6- مروری بر XAML
و...
ویدیوی بسیار جالبی بود