C# Programming Guide
Photo
توی مثال بالا من یک Task با زمان توقف 1 ثانیه ایجاد کردم و تا عدد 100 میره و در این حالت شما میتونید روی دکمه کلیک کنید و ببینید که نرم هست و هیچ هنگی ای توش نیست و نرم افزار هم براحتی کار میکنه. چون Thread.Sleep توی یک ترد دیگه اجرا میشه و await منتظر میمونه تا کارش تموم بشه و بعدش پروگرسبار شما توی ترد اصلی اپدیت میشه. از Task.Delay استفاده نکردم تا بیشتر مفهوم کارش رو متوجه بشید و خودتون بتونید یک تابع awaitable ایجاد کنید.
C# Programming Guide
توی مثال بالا من یک Task با زمان توقف 1 ثانیه ایجاد کردم و تا عدد 100 میره و در این حالت شما میتونید روی دکمه کلیک کنید و ببینید که نرم هست و هیچ هنگی ای توش نیست و نرم افزار هم براحتی کار میکنه. چون Thread.Sleep توی یک ترد دیگه اجرا میشه و await منتظر میمونه…
اگر شما Task و async و await هارو بردارید نرم افزار شما حدود 100 ثانیه تو حالت هنگ میمونه.چون Thread.Sleep توی ترد UI (رابط کاربری) اجرا میشه و نرم افزار شما Freez میشه و دیگه نمیتونید چیزی ببینید یا روی دکمه ای کلیک کنید البته چون تابع Run توی Constructor هست برنامه ی شما 100 ثانیه بعد بالا خواهد اومد.
برای اینکه async و await رو توی دات نت 4.0 داشته باشید باید پکیج Microsoft.Bcl.Async رو توی پروژتون اضافه کنید.
پکیج هارو هم از طریق پنجره ی Package Manager توی ویژوال استادیو براحتی میتونید پیدا کنید و نصب کنید.
روی پروژه راست کلیک کنید و Manage Nuget Packages رو بزنید و از تب Browse پکیج مورد نظر رو جستجو کنید و نصب کنید.
#آموزش
#پکیج
#Package_Manager
#Package
پکیج هارو هم از طریق پنجره ی Package Manager توی ویژوال استادیو براحتی میتونید پیدا کنید و نصب کنید.
روی پروژه راست کلیک کنید و Manage Nuget Packages رو بزنید و از تب Browse پکیج مورد نظر رو جستجو کنید و نصب کنید.
#آموزش
#پکیج
#Package_Manager
#Package
کلید واژه های virtual و override چیست و اصلا چرا ما باید از اینا استفاده کنیم؟ کاربردشون چه زمانی واقعا نیاز میشه؟
C# Programming Guide
کلید واژه های virtual و override چیست و اصلا چرا ما باید از اینا استفاده کنیم؟ کاربردشون چه زمانی واقعا نیاز میشه؟
توی این مثالی که میزنم یکم بیشتر مفهوم استفاده از این کلید واژه ها رو متوجه خواهید شد:
همونطور که میدونید یه سری کد های سیستم عاملی مخصوص اون سیستم عامل هستند و قابلیت اجرا توی سیستم عامل های دیگه رو ندارن مثلا شما توی ویندوز وقتی میخواید پنجره ای رو به کاربر نشون بدید که یک محل ذخیره و یک پوشه رو انتخاب کنه از کلاس FolderBrowserDialog استفاده میکنید ولی نمیتونید از این کلاس توی اندروید استفاده کنید چون این کلاس مخصوص سیستم عامل ویندوز و از توابع API خود ویندوز استفاده میکنه و نمیتونید از اون توی اندروید استفاده کنید چون توابع سیستم عامل ها شبیه هم نیستند و از پایه سیستمشون با هم فرق میکنه یا به عبارتی سیستم عامل ها نرم افزار های متفاوتی نسبت به هم هستند و حتی توی کامپایل به خطا خواهید خورد.
فرض کنید کلاسی دارید که یه سری آدرس های انتخاب شده توسط کاربر توش ذخیره میشه (مثلا محل ذخیره ی تنظیمات نرم افزارتون) و یه سری داده هایی توی این کلاس هست که توی تمام سیستم عامل ها یکسان هستند و توسط کاربر انتخاب میشن مثلا یک String از آدرس محل ذخیره ی انتخاب شده توسط کاربر و ...
حالا شما نمیخواهید قسمت هسته ی کلاس رو دوباره سازی کنید بلکه فقط میخواهید قسمت هایی که مخصوص سیستم عامل های دیگه هست رو مجدد پیاده سازی کنید.و میخواهید هنگامی که متغیر SaveAddress فراخونی شد و مقدارش خالی بود به کلاس کاربر بگید که ادرس رو از کاربر بگیره و توش ذخیره کنه.
توی این حالت کلید واژه های virtual و override به کمک شما میان.
همونطور که میدونید یه سری کد های سیستم عاملی مخصوص اون سیستم عامل هستند و قابلیت اجرا توی سیستم عامل های دیگه رو ندارن مثلا شما توی ویندوز وقتی میخواید پنجره ای رو به کاربر نشون بدید که یک محل ذخیره و یک پوشه رو انتخاب کنه از کلاس FolderBrowserDialog استفاده میکنید ولی نمیتونید از این کلاس توی اندروید استفاده کنید چون این کلاس مخصوص سیستم عامل ویندوز و از توابع API خود ویندوز استفاده میکنه و نمیتونید از اون توی اندروید استفاده کنید چون توابع سیستم عامل ها شبیه هم نیستند و از پایه سیستمشون با هم فرق میکنه یا به عبارتی سیستم عامل ها نرم افزار های متفاوتی نسبت به هم هستند و حتی توی کامپایل به خطا خواهید خورد.
فرض کنید کلاسی دارید که یه سری آدرس های انتخاب شده توسط کاربر توش ذخیره میشه (مثلا محل ذخیره ی تنظیمات نرم افزارتون) و یه سری داده هایی توی این کلاس هست که توی تمام سیستم عامل ها یکسان هستند و توسط کاربر انتخاب میشن مثلا یک String از آدرس محل ذخیره ی انتخاب شده توسط کاربر و ...
حالا شما نمیخواهید قسمت هسته ی کلاس رو دوباره سازی کنید بلکه فقط میخواهید قسمت هایی که مخصوص سیستم عامل های دیگه هست رو مجدد پیاده سازی کنید.و میخواهید هنگامی که متغیر SaveAddress فراخونی شد و مقدارش خالی بود به کلاس کاربر بگید که ادرس رو از کاربر بگیره و توش ذخیره کنه.
توی این حالت کلید واژه های virtual و override به کمک شما میان.
C# Programming Guide
Photo
توی مثال بالا من سه تا کلاس ساختم:
1. کلاس BrowserCore که همون کلاس مشترک بین دو سیستم عامل ویندوز و اندروید هست و نمیخواهید متغیرهاش کپی بشه و دوباره نویسی کنید این کلاس رو یک بار مینویسید و توی همه ی سیستم عامل ها استفاده میشه.همچنین باید در نظر داشته باشید که کار های مشترک بین دو سیستم عامل رو در این کلاس ها باید بنویسید و مثلا کدهای مخصوص ویندوز رو توش ننویسید که توی اندروید اجرا یا کامپایل نمیشه.مسائل مربوط به برنامه نویسی کراس پلتفرم هست که در اینده بیشتر باهاش اشنا میشیم.
2.کلاس AndroidBrowser که کد های مخصوص اندروید رو توش مینویسم که توی سیستم عامل های دیگه قابل اجرا نیست.
3.کلاس WindowsBrowser که کد های مخصوص ویندوز رو توش مینویسیم که توی سیستم عامل های دیگه قابل اجرا نیست.
نکته:در حال حاضر من از کلاس FolderBrowserDialog برای ویندوز استفاده نکردم بیشتر خواستم مفهوم استفاده از اینها رو متوجه بشید.
1. کلاس BrowserCore که همون کلاس مشترک بین دو سیستم عامل ویندوز و اندروید هست و نمیخواهید متغیرهاش کپی بشه و دوباره نویسی کنید این کلاس رو یک بار مینویسید و توی همه ی سیستم عامل ها استفاده میشه.همچنین باید در نظر داشته باشید که کار های مشترک بین دو سیستم عامل رو در این کلاس ها باید بنویسید و مثلا کدهای مخصوص ویندوز رو توش ننویسید که توی اندروید اجرا یا کامپایل نمیشه.مسائل مربوط به برنامه نویسی کراس پلتفرم هست که در اینده بیشتر باهاش اشنا میشیم.
2.کلاس AndroidBrowser که کد های مخصوص اندروید رو توش مینویسم که توی سیستم عامل های دیگه قابل اجرا نیست.
3.کلاس WindowsBrowser که کد های مخصوص ویندوز رو توش مینویسیم که توی سیستم عامل های دیگه قابل اجرا نیست.
نکته:در حال حاضر من از کلاس FolderBrowserDialog برای ویندوز استفاده نکردم بیشتر خواستم مفهوم استفاده از اینها رو متوجه بشید.
کلید واژه ی virtual به شما این امکان رو میده تا تابع خودتون رو بتونید طوری پیاده سازی کنید که در آینده کلاس های دیگه از کلاس شما ارث میبرن بتونن اون تابع رو گسترش بدن یا پیاده سازی مجددش کنن.مثلا شما میتونید توی تابع ChangeSaveAddress که توی کلاس های AndroidBrowser یا WindowsBrowser هست بنویسید base.ChangeSaveAddress تا تابع کلاس بیس شما که BrowserCore هم اجرا بشه و اگر این رو ننویسید تابع ChangeSaveAddress توسط کلید واژه ی override مجدد بارگذاری شده و اون تابع کلاس بیس دیگه صدا زده نخواهد شد.حتی اگر شما کلاس های AndroidBrowser یا WindowsBrowser رو Cast کنید به BrowserCore باز هم تابع BrowserCore اجرا نخواهد شد.طریقه ی Cast کردن:
WindowsBrowser windows = new WindowsBrowser();
var browserCore = (BrowserCore)windows;
browserCore.ChangeSaveAddress();
WindowsBrowser windows = new WindowsBrowser();
var browserCore = (BrowserCore)windows;
browserCore.ChangeSaveAddress();
قابل توجه دوستانی که با ساختار XAML طراحی رابط کاربری WPF انجام میدادن، بخش های دیگری هم برای برنامه نویسی به ساختار XAML برای سیستم عامل های دیگر اضافه شده که بهتر هست در موردش تحقیقاتی انجام بدید و بی خبر نمونید.
به وسیله ساختار XAML ای که باWPF کار میکردید شما قادر خواهی بود رابط کاربری برای نسخه های قدیمی ویندوز و UWP برای نسخه ی ویندوز 10 به بالا نرم افزار طراحی کنید.
به وسیله ی همین ساختار شما قادر خواهی بود به صورت کراس پلتفرم رابط کاربری طراحی کنید برای اندروید و ISO و ویندوز فون و ... در واقع با همون ساختار WPF و اعمال بایندینگ ها و ... شما میتونید برای اندروید هم طراحی رابط کاربری و نرم افزار انجام بدید.
این اعمال با کامپوونت Xamarin Forms انجام میشه. اطلاعات بیشتر در https://www.xamarin.com/forms
به وسیله ی XAML شما قادر خواهید بود با کد سی شارپ و XAML طراحی رابط کاربری سایت انجام بدید و خروجی جاوا اسکریپت و html و css بگیرید.
این اعمال با کامپوننت XAML for HTML5 انجام میشه .اطلاعات بیشتر در https://cshtml5.com
به وسیله ساختار XAML ای که باWPF کار میکردید شما قادر خواهی بود رابط کاربری برای نسخه های قدیمی ویندوز و UWP برای نسخه ی ویندوز 10 به بالا نرم افزار طراحی کنید.
به وسیله ی همین ساختار شما قادر خواهی بود به صورت کراس پلتفرم رابط کاربری طراحی کنید برای اندروید و ISO و ویندوز فون و ... در واقع با همون ساختار WPF و اعمال بایندینگ ها و ... شما میتونید برای اندروید هم طراحی رابط کاربری و نرم افزار انجام بدید.
این اعمال با کامپوونت Xamarin Forms انجام میشه. اطلاعات بیشتر در https://www.xamarin.com/forms
به وسیله ی XAML شما قادر خواهید بود با کد سی شارپ و XAML طراحی رابط کاربری سایت انجام بدید و خروجی جاوا اسکریپت و html و css بگیرید.
این اعمال با کامپوننت XAML for HTML5 انجام میشه .اطلاعات بیشتر در https://cshtml5.com
Microsoft
Xamarin | Open-source mobile app platform for .NET
Xamarin is a free and open source mobile app platform for building native and high-performance iOS, Android, tvOS, watchOS, macOS, and Windows apps in C# with .NET.
کاهش عملیات Boxing و Unboxing در کد:
عملیات boxing و unboxing یک عملیات داخلی فریم وروک است که برای برنامه نویسان C#.Net و VB.Net خودکار انجام میشود و اصلاً متوجه آن نمیشوند (ولی مثلاً برنامه نویسان VC++.Net مجبوراً صراحتاً دستور مربوطه را بنویسند)
دات نت زبانی کاملاً شی گرا است و تا انجا پیش رفته که Struct های ان نیز مطابق اصول شی گرایی هستند ...
تمام Struct های دات نت وراثتی هستند از System.ValueType و آن هم وراثتی است از System.Object
بدین ترتیب سلسه مراتب وراثتی برای Struct ها هم تامین شده که گاهاً میتواند باعث تعجب برنامه نویسان سایر زبانهای شی گرایی گردد.
این کار محاسن زیادی دارد و اجازه شی گرایی یکپارچه را در زبان برنامه نویسی میدهد و خیلی خوب است .
ولی اصول مدیریت داخلی حافظه برای Struct ها با Class ها بسیار بسیار فرق دارد و این در اصل سرچشمه تفاوت این دو ساختار است که من قصد و وقت تشریح ان را ندارم و تاثیری هم در کد ما ندارد.
نکته ای که مهم است ان جا است که دات نت چطور میتواند یک Struct را با یک سیستم مدیریت حافظه متفاوت در یک Object که Class است جای دهد؟؟؟
کنترل این عملیات به صورت خودکار بر عهده محیط CLR است و نام این عملیات box و unbox است.
عمل boxing چیزی شبیه این است ... (شبیه است ولی این طوری نیست!)
کد:
public class box
{
public structtype value;
}
//....
structtype value1 = ...;
object value2 = new box() { value = value1 };
که طی آن یک struct (مثل value1) به یک class (مثل value2) تبدیل میشود.
عمل unboxing چیزی شبیه این است ... (شبیه است ولی این طوری نیست!)
کد:
public class box
{
public structtype value;
}
//....
object value2 ...;
structtype value1 = ((box)value2).value;
که طی آن یک struct که داخل یک object است (مثل value2) به یک struct واقعی و آزاد (مثل value1) تبدیل میشود.
نکته مهم و قابل توجه انجا است که عملیات فوق بسیار بسیار پرسرعت و با بازدهی بالا است و اصلاً با کدهایی که دیدید برابر نیست و مستقیم و با سرعت بالا توسط هسته CLR انجام میشود و در هر اجرای یک کپی بسیار کوچک اطلاعات به حجم Struct هم رخ میدهد.
ولی با وجود پرسرعت بودن، انجام عمل فوق در یک حلقه عظیم میتوانید باعث افت سرعت شود،
مجدد تاکید میکنم که حلقه ای 100 بار انجام شود سرعت را 100 برابر کاهش میدهد و حلقه 1000 و 10000 و ... هم جای خود و در نهایت افزایش صفر مشکل ساز میشود.
کد عملی مثل این نمونه از boxing و unboxing است:
کد:
int v1 = ...;
object v2 = v1;
int v3 = (int)v2;
البته کد فوق به ذات مشکل خاص سرعتی ندارد ولی در حلقه ای که چند صفر ناقابل به ان اضافه کند ... !
ولی کد زیر اصلاً boxing و unboxing نیست : (گرچه ظاهرش یکسان است!)
کد:
string v1 = ...;
object v2 = v1;
string v3 = (string)v2;
چون کد اول Integer بود و Integer یک Struct است ولی String خودش یک Class است و نیازی به boxing ندارد.
نتیجتاً شما باید تا حد امکان از پاسکاری Struct ها به Object ها جلوگیری کنید.
=====
همانطور که اول گفتم شما باید مراقب کدنویسی داخلی ناپیدا توابع آماده هم باشید.
مثلا کد ساده زیر را در نظر بگیرید ...
کد:
//C#.Net
int[] array = new int[512];
int item = 0;
for (int index = array.Length -1 ; index >= 0; —index)
{
array[index] = item++;
}
//...
//بحث اصلاً سر کدهای قبلی تا این نوشته نیست
//...
System.Array.Sort(array);
یک کد ساده مختصر مفید و در اصل یک خطی برای مرتب کردن عناصر یک آرایه ... فقط یک خط ! (فقط تک خط آخری)
حالا اگر بگم تک خط کد فوق در بدترین شرایط باعث ...
- دو حلقه تو در تو مقایسه با حدود 130 هزار مقایسه ...
- 260 هزار box ...
- 260 هزار unbox ...
- جابه جایی و انتقال نزدیک 2MB اطلاعات در RAM میشود ...
حالا چه فکر میکنید؟؟؟
حالا فکر کنید (در unity و بازی سازی) قرار باشد کد فوق در متدی مثل Game.Update قرار داشته باشد و قرار باشد در هر ثانیه 60 باری اجرا شود !!!
برنامه شما در یک ثانیه 120MB اطلاعات را فقط به خاطر همین یک خط دستور در RAM جابه جا خواهد کرد!
حتماً باز هم میگید چرا برنامه کند است!!!
یادتان نرود اکثر کدهای برنامه نویسی شما همان تعداد خط کد ظاهری که شما تایپ میکنید نیستند.
(الگوریتم مرتب سازی یک چیز کلی و استاندارد در همه زبانها است و قرار نیست کاری در مریخ انجام شود، اگر دستور اجرا میکنید نباید انتظار داشته باشید که با جادو و دستور در یک آن در CPU اجرا شود، برای انجام عملیاتها یا شما باید الگوریتم را بنویسید یا کس دیگری قبلاً آن را نوشته و در هر دو صورت این الگوریتم هزینه ای برای اجرا دارد.)
عملیات boxing و unboxing یک عملیات داخلی فریم وروک است که برای برنامه نویسان C#.Net و VB.Net خودکار انجام میشود و اصلاً متوجه آن نمیشوند (ولی مثلاً برنامه نویسان VC++.Net مجبوراً صراحتاً دستور مربوطه را بنویسند)
دات نت زبانی کاملاً شی گرا است و تا انجا پیش رفته که Struct های ان نیز مطابق اصول شی گرایی هستند ...
تمام Struct های دات نت وراثتی هستند از System.ValueType و آن هم وراثتی است از System.Object
بدین ترتیب سلسه مراتب وراثتی برای Struct ها هم تامین شده که گاهاً میتواند باعث تعجب برنامه نویسان سایر زبانهای شی گرایی گردد.
این کار محاسن زیادی دارد و اجازه شی گرایی یکپارچه را در زبان برنامه نویسی میدهد و خیلی خوب است .
ولی اصول مدیریت داخلی حافظه برای Struct ها با Class ها بسیار بسیار فرق دارد و این در اصل سرچشمه تفاوت این دو ساختار است که من قصد و وقت تشریح ان را ندارم و تاثیری هم در کد ما ندارد.
نکته ای که مهم است ان جا است که دات نت چطور میتواند یک Struct را با یک سیستم مدیریت حافظه متفاوت در یک Object که Class است جای دهد؟؟؟
کنترل این عملیات به صورت خودکار بر عهده محیط CLR است و نام این عملیات box و unbox است.
عمل boxing چیزی شبیه این است ... (شبیه است ولی این طوری نیست!)
کد:
public class box
{
public structtype value;
}
//....
structtype value1 = ...;
object value2 = new box() { value = value1 };
که طی آن یک struct (مثل value1) به یک class (مثل value2) تبدیل میشود.
عمل unboxing چیزی شبیه این است ... (شبیه است ولی این طوری نیست!)
کد:
public class box
{
public structtype value;
}
//....
object value2 ...;
structtype value1 = ((box)value2).value;
که طی آن یک struct که داخل یک object است (مثل value2) به یک struct واقعی و آزاد (مثل value1) تبدیل میشود.
نکته مهم و قابل توجه انجا است که عملیات فوق بسیار بسیار پرسرعت و با بازدهی بالا است و اصلاً با کدهایی که دیدید برابر نیست و مستقیم و با سرعت بالا توسط هسته CLR انجام میشود و در هر اجرای یک کپی بسیار کوچک اطلاعات به حجم Struct هم رخ میدهد.
ولی با وجود پرسرعت بودن، انجام عمل فوق در یک حلقه عظیم میتوانید باعث افت سرعت شود،
مجدد تاکید میکنم که حلقه ای 100 بار انجام شود سرعت را 100 برابر کاهش میدهد و حلقه 1000 و 10000 و ... هم جای خود و در نهایت افزایش صفر مشکل ساز میشود.
کد عملی مثل این نمونه از boxing و unboxing است:
کد:
int v1 = ...;
object v2 = v1;
int v3 = (int)v2;
البته کد فوق به ذات مشکل خاص سرعتی ندارد ولی در حلقه ای که چند صفر ناقابل به ان اضافه کند ... !
ولی کد زیر اصلاً boxing و unboxing نیست : (گرچه ظاهرش یکسان است!)
کد:
string v1 = ...;
object v2 = v1;
string v3 = (string)v2;
چون کد اول Integer بود و Integer یک Struct است ولی String خودش یک Class است و نیازی به boxing ندارد.
نتیجتاً شما باید تا حد امکان از پاسکاری Struct ها به Object ها جلوگیری کنید.
=====
همانطور که اول گفتم شما باید مراقب کدنویسی داخلی ناپیدا توابع آماده هم باشید.
مثلا کد ساده زیر را در نظر بگیرید ...
کد:
//C#.Net
int[] array = new int[512];
int item = 0;
for (int index = array.Length -1 ; index >= 0; —index)
{
array[index] = item++;
}
//...
//بحث اصلاً سر کدهای قبلی تا این نوشته نیست
//...
System.Array.Sort(array);
یک کد ساده مختصر مفید و در اصل یک خطی برای مرتب کردن عناصر یک آرایه ... فقط یک خط ! (فقط تک خط آخری)
حالا اگر بگم تک خط کد فوق در بدترین شرایط باعث ...
- دو حلقه تو در تو مقایسه با حدود 130 هزار مقایسه ...
- 260 هزار box ...
- 260 هزار unbox ...
- جابه جایی و انتقال نزدیک 2MB اطلاعات در RAM میشود ...
حالا چه فکر میکنید؟؟؟
حالا فکر کنید (در unity و بازی سازی) قرار باشد کد فوق در متدی مثل Game.Update قرار داشته باشد و قرار باشد در هر ثانیه 60 باری اجرا شود !!!
برنامه شما در یک ثانیه 120MB اطلاعات را فقط به خاطر همین یک خط دستور در RAM جابه جا خواهد کرد!
حتماً باز هم میگید چرا برنامه کند است!!!
یادتان نرود اکثر کدهای برنامه نویسی شما همان تعداد خط کد ظاهری که شما تایپ میکنید نیستند.
(الگوریتم مرتب سازی یک چیز کلی و استاندارد در همه زبانها است و قرار نیست کاری در مریخ انجام شود، اگر دستور اجرا میکنید نباید انتظار داشته باشید که با جادو و دستور در یک آن در CPU اجرا شود، برای انجام عملیاتها یا شما باید الگوریتم را بنویسید یا کس دیگری قبلاً آن را نوشته و در هر دو صورت این الگوریتم هزینه ای برای اجرا دارد.)
توی سی شارپ 7 شما میتونید برای یک تابع چندین خروجی متفاوت بدید، قبلا اینطور بود که شما همیشه باید یک خروجی میداشتید و در نهایت اگر پارامتر هاتون زیاد باشه مجبورین کلاس بسازید و پارامتر های خروجی رو توی اون کلاس بریزید ولی توی سی شارپ نسخه ی 7 (ویژوال استادیو 2017) شما میتونید برای یک تابع چند خروجی داشته باشید.
برای مثال:
برای مثال:
برای اینکه بتونید همیشه سریع کد بزنید سعی کنید عادت کنید به استفاده از Code Snippets ها، قطعه کد ها به شما کمک میکنن تا با تایپ چند کاراکتر و سپس استفاده از دابل تب کد کامل براتون تایپ بشه در این حالت شما میتونید مقادیر رو هم تعویض کنید.در ادامه یک ویدئوی کوتاه براتون میذارم که بدونید از Code Snippets ها چطوری استفاده کنید.دابل تب به این معنی هست که شما کلید Tab کیبرد رو دوبار پشت سر هم بزنید.