انتشار ویرایش نخست از NET Core.

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

NET Core. روی سیستم عامل‌های ویندوز، مک و توزیع‌های مختلف لینوکس از جمله RedHat و Ubuntu قابل اجراست. زبان‌های برنامه نویسی C#، VB و #F به همراه بسیاری از ساختارهای مدرن برنامه‌نویسی نظیر جنریک‌ها، زبان پرس‌وجوی مجتمع‌شده (LINQ)، برنامه‌نویسی غیرهمزمان(async) و ... توسط آن پشتیبانی می‌شود.

کتابخانه‌ها، کامپایلر، Core Runtime ، زبان‌ها و ابزارهای آن‌ها به‌طور کامل سورس باز بوده و در Github جایی که می‌توان در پروژه‌ها همکاری نمود، هاست شده و به‌طور کامل پشتیبانی می‌شود.

شروع کار با NET Core.:

در صورتی که از ویژوال استادیو ویرایش ۲۰۱۵ استفاده می‌کنید ابتدا باید آپدیت شماره ۳ آن را دریافت کنید و سپس ابزار NET Core. برای ویژوال استادیو را نصب نمایید.

در صورتی که از ویژوال استادیو استفاده نمی‌کنید، به‌طور مثال اگر از ابزار Visual Studio Code به صورت رایگان و با نصب افزونه #C برای آن استفاده می‌کنید، SDK مربوط به NET Core. برای سیستم‌عامل ویندوز موجود است. همچنین اگر از از لینوکس، مک و یا هرچیز دیگری استفاده می‌کنید به http://dot.net مراجعه کنید و نسخه‌ی مورد نظر خود را دانلود کنید.

اگر می‌خواهید تمام نسخه‌های موجود برای NET. و یا NET Core. را مشاهده کنید از این جدول استفاده کنید.

NET Core. چیست؟

در اینجا به‌طور انتزاعی اطلاعاتی از قابلیت‌های آن از وبلاگ رسمی NET. آمده است:

     • چند سکویی بودن: به این معنی که قابلیت اجرا روی ویندوز، مک و لینوکس را دارا می‌باشد.

     • قابل توسعه انعطاف پذیر: به این معنی که NET Core. می‌تواند درون نرم‌افزار تولید شده‌ی شما برای نصب قرار بگیرد و یا به‌صورت مستقل بر روی ماشین کاربر نصب گردد.

     • ابزار‌های قوی خط فرمان: تمام سناریوهای این محصول قابل اجرا و اعمال از طریق خط فرمان (Command Line) هستند.

     • سازگاری: NET Core. از طریق کتابخانه استاندارد NET.  کاملا با فریم ورک اصلی .NET ، Xamarin و مونو سازگار است.

     • سورس باز بودن: NET Core. سورس باز است و تحت مجوزهای MIT و Apache 2 ارائه شده است. مستندات آن تحت مجوز CC-BY ارائه شده است. NET Core. یک پروژه مربوط به NET Foundation. می‌باشد.

     • پشتیبانی کامل توسط مایکروسافت: NET Core. توسط بخش پشتیبانی آن در مایکروسافت پشتیبانی می‌شود.

NET Core. از بخش‌های اصلی زیر تشکیل شده است:

     • یک بخش شامل NET Runtime. که نوع سیستم، بارگیر اسمبلی‌ها، garbage collector ، interop محلی و سایر سرویس‌های پایه را شامل می‌شود.

     • یک بخش شامل کتابخانه‌های فریم ورک که نوع‌های داده‌ای اولیه، نوع‌های ترکیبی App و ابزارهای کاربردی اساسی را شامل می‌شود.

     • یک بخش شامل SDKها و کامپایلرهای زبان که تجربه توسعه‌ی برنامه در ابتدایی‌ترین شکل را به شما منتقل می‌کند که در SDK مربوط به NET Core. موجود است.

     • و بخش هاست مربوط به Appهای دات‌نت که برای اجرای برنامه‌های NET Core. استفاده می‌شود. این بخش runtimeها و اسمبلی‌های لازم برای اجرای برنامه را انتخاب وهاست می‌کند.

مستندات بیشتری نیز توسط مایکروسافت ارائه شده که در صورت تمایل می‌توانید آن‌ها را در اینجا دنبال کنید. همچنین مستندات مربوط به ASP.NET Core‌ نیز در اینجا قابل مشاهده می‌باشد.

 

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

نکات کاربردی و ساده جهت افزایش سرعت وب‌سایت‌های ASP.NET

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

برخی از مهمترین نکات جهت افزایش سرعت یک وب‌سایت ASP.NET در زیر آمده است:

۱- به‌روز رسانی NET Framework. مربوط به وب‌سایت

ویرایش فعلی فریم ورک سایت خود را بررسی کنید. تنظیم آن به مقدار 4.5 (آخرین ویرایش فعلی) باعث افزایش بهره‌وری و سرعت خواهد شد. NET 4.5. دارای یک Garbage Collector بسیار قدرتمند است که می‌تواند heap‌های بسیار بزرگ را مدیریت کند. از بهینه‌سازی انجام شده دیگر در این نسخه، می توان به بهینه شدن چند هسته‌ای کامپایلر JIT و قابلیت معلق سازی برنامه‌های ASP.NET اشاره کرد. این بهینه‌سازی‌ها نیازی به تغییر کد برنامه ندارند.

۲- اعمال Caching

۱-۲- از صفت OutputCache برای صفحاتی که پویا نیستند و میزان بازدید آن‌ها زیاد است استفاده کنید. برای استفاده از این صفت در MVC می‌توان آن را به یک Controller به‌خصوص یا کل کلاس Controller اختصاص داد. برای مثال در زیر کنترلر Index برای ۲۰ ثانیه کش شده است:

 

[OutputCache(Duration = 20, VaryByParam = "None")]
public ActionResult Index(string Id)
{

}

۲-۲- سعی کنید عملیات I/O مورد نیاز برای داده‌ها را از دیسک کاهش دهید. به‌جای آن از کش کردن داده‌ها در حافظه‌ی اصلی کمک بگیرید. با این‌کار جلوی بسیاری از عملیات پر‌هزینه مانند کوئری‌های مکرر برای دریافت داده را خواهید گرفت. به علاوه کش کردن داده یک خاصیت مهم دیگر نیز دارد و آن این است که وقتی Data Source موقتا با مشکل مواجه می‌شود داده‌ها از دسترس خارج نمی شوند. دات نت کلاس‌های بسیار خوبی برای استفاده از امکانات کش در ASP.NET فراهم کرده است. این کلاس‌ها در فضای نام System.Runtime.Caching موجودند.

۳- نگهداری اطلاعات CSS و JavaScript خارج از صفحه

اضافه‌کردن کلاس‌های CSS و یا کدهای جاوا اسکریپت به‌صورت inline در Viewها باعث تولید مجدد آنها در هر بار درخواست صفحه خواهد شد. با این کار شما مزایای کش شدن صفحه را از دست خواهید داد. بنابراین همیشه این کدها را خارج از صفحه مورد استفاده نگهداری کنید و فقط ارجاعات آنها را (link) به صفحه اضافه کنید.

۴- فشرده سازی فایل

عموما در بیشتر وب‌سایت‌ها درخواست‌های مکرر و زیادی برای فایل‌های استاتیک از وب‌سرور داده می‌شود. این فایل‌ها می‌توانند فشرده شوند تا پهنای باند کمتری در هر درخواست مصرف شود. یک تنظیم بسیار عالی برای این‌کار در IIS 7  و بالاتر وجود دارد:

<configuration>  
    <system.webServer>    
        <urlCompression doStaticCompression=true  doDynamicCompression=true />  
    </system.webServer> 
</configuration> 

به نظر تگ  urlCompression کمی برای این‌کار عجیب به‌نظر می‌رسد ولی این تگ واقعا URL را فشرده نمی‌کند. این تگ محتوای اطلاعاتی که قرار است به مرورگر کاربر فرستاده شود را فشرده می‌کند. برای فعال سازی آن کافی است مقادیر ویژگی‌های این تگ به true تنظیم شود تا عمل فشرده سازی انجام شود و پهنای باند استفاده شده کاهش یابد.

۵- بسته‌بندی (Bundling) و کوچک سازی (Minification)

فایل‌های CSS و JavaScripts می‌توانند در یک فایل تکی قرار گیرند. با این‌کار تعداد درخواست‌های Http به وب‌سرور کاهش می‌یابد. همچنین با عملیات Minification بسیار از فضا‌های خالی این‌فایل‌ها حذف می‌شوند و در نتیجه حجم فایل ارسالی کاهش خواهد یافت. ابزار‌های بسیاری در وب برای این‌کار موجود است.

۶- استفاده از CDN

بهتر است فایل‌های جاوا اسکریپت پر استفاده و معروف مانند Jquery را به جای این‌که در یک هاست شخصی قرار دهیم آنها را در CDN بگذاریم. سرورهای CDN برای ارائه فایل‌های استاتیک پراستفاده طراحی شدند و به‌دلیل در نظر گرفتن موقعیت جغرافیایی درخواست کننده و سرعت بالا و پهنای باند بالای سرورهای آنها بسیار سریعتر از هاست شخصی عمل می‌کنند. همچنین احتمال زیادی وجود دارد که مرورگر به طور خودکار فایل‌های JavaScript را با درنظر گرفتن درخواست‌های متعدد با URL یکسان کش کند. یکی از معروف‌ترین سرویس‌های ارائه دهنده CDN، این سایت است.

۷- کنترل کردن درخواست‌های مربوط به تصاویر

۱-۷- استفاده از تکنیک Image Sprits:

با استفاده از تکنیک می‌توان تعداد زیادی تصویر کوچک را در قالب یک تصویر بزرگ ادغام کرد و سپس با استفاده از دستورات CSS هر قسمت را جداگانه فراخوانی کرد. این کار باعث کاهش تعداد درخواست‌ها از وب‌سرور و افزایش قابل توجه سرعت می‌شود. ابزارهای زیادی برای ایجاد این‌تصاویر و CSS تولیدی وجود دارد.

۲-۷- استفاده از Base64 Data URIs:

با استفاده از این تکنیک شما می‌توانید بدون نیاز به درخواست مستقیم تصویر از وب‌سرور به تصویر خود دست‌پیدا کنید.

۸- ترتیب رندر شدن اسکریپت‌ها

تگ‌های <script> را به انتهای هر صفحه منتقل کنید. این کار از این جهت مفید است که مرورگر هنگام رندر صفحه وقتی به تگ <script> می‌رسد تا اتمام کامل پردازش آن صبر می‌کند و سپس ادامه می‌دهد. این کار باعث می‌شود محتوای  HTML صفحه سریعتر از مابقی بخش‌ها رندر شده و به کاربر نمایش داده شود. البته گاهی اوقات مانند زمانی که فایل‌های CSS به این اسکریپت‌ها نیازمند است؛ امکان انتقال آن‌ها به انتهای صفحه وجود ندارد.

روش دیگر اینکار استفاده از صفت‌های این تگ است:

<script src=some.js defer>

</script>

استفاده از صفت defer باعث می‌شود اجرای اسکریپت تا پردازش کل صفحه به تعویق بیافتد.

<script src=some.js async>

</script>

استفاده از صفت async باعث می‌شود اجرای اسکریپت به صورت غیرهمزمان در اولین فرصت انجام شود.

۹- حذف ماژول‌هایHTTP  پیش‌فرض ASP.NET

ASP.NET دارای ماژول‌های HTTP بسیاری است که آماده گرفتن درخواست و پردازش هستند، این ماژول‌ها می‌توانند کل Pipeline را تسخیر کنند حتی درصورتی که برای برنامه‌ی شما پیکربندی نشده باشند.

همه‌ی این ماژول‌های پیش‌فرض در یک فایل machine.config در مسیر:

"WINDOWS%\Microsoft.NET\Framework\%VERSION%\CONFIG%"

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

۱۰- کامپایل پروژه در حالت Release

همیشه گزینه Build پروژه را درحالت Release قرار دهید. این‌کار باعث می‌شود بسیاری از متادیتا‌ها و اطلاعات اضافی که صرفا جهت Debug برنامه کاربرد دارد از اسمبلی حذف شود و عملیات بهینه‌سازی برای اجرا روی کد نهایی انجام شود.

اگر فکر می‌کنید با درنظر گرفتن تمام این موارد دیگر نیاز به انجام هیچ‌کاری برای افزایش سرعت وب‌سایت ندارید؛ سخت در اشتباه هستید چون هرچقدر تجربه‌ی شما در زمینه طراحی و توسعه وب‌سایت و کار با ASP.NET بالاتر برود نکات بیشتری را باید رعایت کنید تا سایت سریعتری داشته باشید. برای رسیدن به این منظور تلاش کنید چون هرکسی می‌تواند با استفاده از یک CMS و یا این ابزارها یک سایت معمولی طراحی کند.

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

تغییر ویرایش زبان پروژه در ویژوال استادیو

می‌توان ویرایش زبان برنامه نویسی مورد نظر را (در صورت تمایل) در ویژوال استادیو تغییر داد. برای مثال اگر نمی‌خواهید از C# 6.0 در ویژوال استادیو ۲۰۱۵ استفاده کنید، می‌توانید ویرایش آن را به نسخه 5.0 #C تغییر دهید.

برای اینکار در ویژوال استادیو بر روی نام پروژه مورد نظر کلیک راست کرده و گزینه Properties را انتخاب کنید. سپس برگه‌ی Build را انتخاب کنید و از انتهای صفحه باز شده بر روی Advance کلیک کنید:

 

به طور پیش فرض هر نسخه از ویژوال استادیو با یک نسخه از زبان#C ارائه شده است:

۱- ویژوال استادیو ۲۰۱۵ - C# 6.0

۲- ویژوال استادیو ۲۰۱۳ - C# 5.0

۳- ویژوال استادیو ۲۰۱۲ - C# 5.0

۴- ویژوال استادیو ۲۰۱۰ - C# 4.0

۵- ویژوال استادیو ۲۰۰۸ - C# 3.0

۶- ویژوال استادیو ۲۰۰۵ - C# 2.0

۷- ویژوال استادیو دات نت ۲۰۰۳ - C# 1.2

۸- ویژوال استادیو دات نت ۲۰۰۲ - C# 1.0

بدیهی است که به ازای هر پروژه می‌توان از ویرایش‌های مختلف زبان بهره جست.

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

موجودیت‌های مرتبط در Entity Framework

EF از سه روش بارگیری با اشتیاق (Eager Loading)، بارگیری تنبل (Lazy Loading) و بارگیری صریح (Explicit Loading) پشتیبانی می‌کند.

۱. بارگیری مشتاقانه (Eagerly Loading)

Eager Loading فرایندی است که طی آن یک کوئری برای یک نوع موجودیت، موجودیت‌های مرتبط با آن را به عنوان بخشی از کوئری نیز Load می‌کند. برای استفاده از Eager Loading باید از متد Include استفاده کنیم. برای مثال، کوئری زیر همه‌ی بلاگ‌ها و پست‌های مرتبط با هر وبلاگ را Load خواهد کرد:

using (var context = new BloggingContext()) 
{ 
    // دریافت همه وبلاگ‌ها همراه پست‌های مرتبط‌شان
    var blogs1 = context.Blogs 
                          .Include(b => b.Posts) 
                          .ToList(); 
 
    // دریافت یک وبلاگ و پست‌های مربوط به آن
    var blog1 = context.Blogs 
                        .Where(b => b.Name == "ADO.NET Blog") 
                        .Include(b => b.Posts) 
                        .FirstOrDefault(); 
 
    // دریافت همه وبلاگ‌ها همراه پست‌های مرتبط‌شان از طریق رشته برای مشخص نمودن رابطه
    var blogs2 = context.Blogs 
                          .Include("Posts") 
                          .ToList(); 
 
    // دریافت یک وبلاگ‌ به‌خصوص همراه پست‌های مرتبط‌اش از طریق رشته برای مشخص نمودن رابطه
    var blog2 = context.Blogs 
                        .Where(b => b.Name == "ADO.NET Blog") 
                        .Include("Posts") 
                        .FirstOrDefault(); 
}

توجه کنید که Include یک متد توسعه یافته (Extension Method) در فضای نام System.Data.Entity است. برای استفاده از این متد باید این فضای نام را به برنامه اضافه کنید.

۱-۱. بارگیری مشتاقانه چند سطحی (Eager Loading Multiple Levels)

این امکان وجود دارد که چندین سطح مختلف از Entity های مرتبط را Load کنیم. مثال زیر روش انجام این‌کار را برای خواص راهبردی (Navigation Property) نوع Collection و نوع Reference را بیان می‌کند:

using (var context = new BloggingContext()) 
{ 
    // دریافت تمامی وبلاگ‌ها به همراه همه‌ی پست‌ها و همه‌ی کامنت‌های پست‌ها
    var blogs1 = context.Blogs 
                       .Include(b => b.Posts.Select(p => p.Comments)) 
                       .ToList(); 
 
    // دریافت تمام پروفایل‌‌ کاربران و آواتار مربوط به هرکدام
    var users1 = context.Users 
                        .Include(u => u.Profile.Avatar) 
                        .ToList(); 
 
    // دریافت همه‌ی وبلاگ‌ها به همراه تمامی پست‌های آن‌ها و کامنت‌های مربوطه از طریق معرفی رابطه به صورت رشته‌ای
    var blogs2 = context.Blogs 
                       .Include("Posts.Comments") 
                       .ToList(); 
 
    // دریافت پروفایل تمامی کاربران و آواتار مربوط به آن‌ها از طریق معرفی رابطه به صورت رشته‌ای
    var users2 = context.Users 
                        .Include("Profile.Avatar") 
                        .ToList(); 
}

توجه کنید که در زمان نگارش این مقاله امکان فیلتر نمودن موجودیت‌های مرتبط، برای Load وجود ندارد و متد Include همیشه تمام موجودیت‌های مرتبط را خواهد آورد.

۲. بارگیری تنبل (Lazy Loading)

Lazy Loading فرایندی است که طی آن یک Entity یا یک مجموعه از Entityها به صورت خودکار زمانی که برای اولین بار موجودیت (های) یک خاصیت (Property) مورد دستیابی قرار می‌گیرد از دیتابیس Load‌ خواهد (خواهند) شد. زمانی که از موجودیت نوع POCO استفاده می کنید Lazy Loading از طریق ایجاد یک نمونه از نوع‌های پروکسی مشتق شده و سپس override نمودن پراپرتی‌های virtual برای اضافه نمودن قابلیت Loading قابل استفاده هستند.

به‌طور مثال زمانی که از کلاس موجودیت Blog تعریف شده در زیر استفاده می‌کنید، همه‌ی Post مرتبط، زمانی که برای اولین بار از خاصیت راهبردی Posts استفاده می‌کنید، Load خواهند شد:

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  
 
    public virtual ICollection<Post> Posts { get; set; }  
}

۱-۲. خاموش نمودن Lazy Loading برای خاصیت‌های راهبردی خاص

برای خاموش نمودن خاصیت Lazy Loading برای مثال در خاصیت مجموعه‌ای Posts، کافی است که عبارت virtual را از آن حذف کنیم:

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  
 
    public ICollection<Post> Posts { get; set; }  
}

نکته: امکان Load مجموعه Posts پس از این کار همچنان از طریق Eager Loading یا روش Explicitly Loading (توضیح در ادامه) وجود خواهد داشت.

۲-۲. خاموش کردن کامل Lazy Loading برای تمامی موجودیت‌ها

برای خاموش کردن کامل Lazy Loading می‌توان از flag مربوط به این‌کار در خاصیت Configuration کمک گرفت. برای مثال:

public class BloggingContext : DbContext 
{ 
    public BloggingContext() 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
    } 
}

نکته: امکان Load همه‌ی موجودیت‌های مرتبط پس از این کار همچنان از طریق Eager Loading یا روش Explicitly Loading (توضیح در ادامه) وجود خواهد داشت.

۳. بارگیری با صراحت (Explicity Loading)

حتی زمانی که Lazy Loading‌ خاموش است امکان استفاده از آن برای موجودیت‌های مرتبط وجود دارد. اما برای این‌کار باید با یک فراخوانی صریح انجام شود. برای این‌کار باید از متد Load پس از فراخوانی موجودیت‌های مرتبط استفاده کنید. برای مثال:

using (var context = new BloggingContext()) 
{ 
    var post = context.Posts.Find(2); 
 
    // دریافت وبلاگ مربوط به پست مشخص شده
    context.Entry(post).Reference(p => p.Blog).Load(); 
 
    //دریافت وبلاگ مربوط به پست مشخص شده با کمک رشته  
    context.Entry(post).Reference("Blog").Load(); 
 
    var blog = context.Blogs.Find(1); 
 
    // دریافت همه پست‌های مرتبط با یک وبلاگ 
    context.Entry(blog).Collection(p => p.Posts).Load(); 
 
    //دریافت پست‌های یک وبلاگ از طریق معرفی یک رشته برای رابطه
    context.Entry(blog).Collection("Posts").Load(); 
}

نکته: توجه کنید که متد Reference زمانی که یک موجودیت دارای خاصیت راهبردی به یک موجودیت منفرد است استفاده می‌شود (مثل زمانی که یک رابطه یک به یک موجود باشد). همچنین زمانی که یک موجودیت از کلاس فعلی دارای یک خاصیت راهبردی به مجموعه از موجودیت‌ها را دارد (مثل زمانی که رابطه یک به چند داریم) از متد Collection استفاده می‌کنیم.

۱-۳. فیلتر نمودن اطلاعات زمانی که از روش Explicit Loading برای موجودیت‌های مرتبط استفاده شده باشد.

متد Query امکان دستیابی به کوئری که Entity Framework قرار است از آن برای دستیابی به موجودیت‌های مرتبط استفاده کند را فراهم می‌کند. پس از آن می‌ةوان از دستورات LINQ برای ایجاد هرگونه فیلتر دلخواه بر روی‌ کوئری پیش از اجرای آن با کمک یکی از متدهای توسعه یافته LINQ مانند ToList یا Load یا ... استفاده نمود.

از متد Query می‌توان در هر دو حالت خواص راهبردی Reference یا Collection استفاده نمود ولی این کار بیشتر برای خواص راهبردی Collection برای فیلتر کردن بخشی از مجموعه که قرار است Load شود کاربرد دارد. برای مثال:

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 
 
    //دریافت همه‌ی پست‌های دارای تگ
    // 'entity-framework' 
    // برای وبلاگ مشخص شده
    context.Entry(blog) 
        .Collection(b => b.Posts) 
        .Query() 
        .Where(p => p.Tags.Contains("entity-framework") 
        .Load(); 
 
    //دریافت همه‌ی پست‌های دارای تگ
    // 'entity-framework' 
    // برای وبلاگ مشخص شده از طریق مشخص نمودن رابطه با رشته 
    context.Entry(blog) 
        .Collection("Posts") 
        .Query() 
        .Where(p => p.Tags.Contains("entity-framework") 
        .Load(); 
}

زمانی که از متد Query بهره می‌برید، بهتر است ویژگی Lazy Loading را به‌طور کامل برای خواص راهبردی خاموش کنید. به این دلیل که ممکن است کل collection مرتبط با خواص راهبردی یک موجودیت پیش یا پس از ایجاد فیلتر بر روی کوئری به طور خودکار توسط Lazy Loading لود گردد.

نکته: زمانی که ارتباط را به‌جای استفاده از عبارات lambda از یک string ساده مشخص می‌کنید، خروجی IQueryable جنریک نخواهد بود و معمولا یک تبدیل با استفاده از متد Cast در این‌جا نیاز خواهد بود.

استفاده از متد Query برای شمارش موجودیت‌های مرتبط بدون Load آن‌ها

گاهی اوقات لازم است بدانیم به یک موجودیت چه تعداد موجودیت وابسته (مرتبط) است بدون آنکه نیاز باشد تمام آن‌ها را از دیتابیس فراخوانی کنیم. به این دلیل که فراخوانی همه‌ی موجودیت‌های مرتبط به هیچ عنوان مقرون به صرفه نخواهد بود و هزینه‌ی زیادی خواهد داشت، در اینجا EF یک امکان بسیار عالی را در اختیار ما قرار داده است. برای این کار کافی است از متد Query و متد Count مربوط به LINQ به‌طور همزمان و به شکل زیر استفاده کنیم:

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 
 
    // شمارش تعداد پست‌های یک وبلاگ  
    var postCount = context.Entry(blog) 
                          .Collection(b => b.Posts) 
                          .Query() 
                          .Count(); 
}



  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

چندتا کارمند مایکروسافت لازمه تا یه لامپ عوض بشه؟

این مقاله در مورد روال کاری شرکت مایکروسافت در مواجه با خطاهای متداول است. این مقاله را فقط در اینجا کپی کردم. علت این بود که سایتی که این مقاله در آن موجود بود در زمان نگارش این مطلب فیلتر شده بودو از آنجا که این یک مقاله خوب (ترجمه خوب) است؛ ممکن است دسترسی به آن برای خیلی‌ها مقدور نباشد. لینک منبع در انتهای این صفحه آمده است.

متن زیر ترجمه ی من از یک مقاله مشهور توسط Eric Lippert است که در سال 2003 نوشته شد و من خواندنش رو به همه ی دوستان توصیه می کنم. عبارت «عوض کردن لامپ» که در عنوان مقاله آمده، کنایه از یک قابلیت غیرواقعی مورد بحث در مقاله به اسم ChangeLightBlubWindowHandlerEx است.

Joe Bork یک مقاله خوب نوشته که در آن تصمیم هایی را که برای رفع یا عدم رفع خطاهای نرم افزاری توضیح داده. این به اون معنیه که من می تونم از روی این مورد توی لیست نوشته های مهم آیندم رد بشم. ممنونم Joe!

اما حالا که بحثش پیش اومده، من می خوام یکمی درباره اون چیزی که Joe گفته بیشتر توضیح بدم. نظرات اون کلی تر از بحث صرفا رفع خطاهای نرم افزاریه. 

یک خطای نرم افزاری، نوعی تغییر در رفتار محصول است و همه تغییرات به یک اندازه هزینه دارند و روال یکسانی را طی می کنند.

پیشتر، زمانی که من برخی امکانات رو به موتورهای اسکریپتی اضافه می کردم، مردم به من ایمیل میزدن و می پرسیدن تا برخی ویژگی های خاص رو براشون پیاده سازی کنم. معمولا این ویژگی ها حالت "فعال-غیر فعال" داشتند. -- ویژگی هایی که مشکلات اختصاصی اونا رو حل می کرد. مثلا، «من ChangeLightBulbWindowHandlerEx رو برای فراخوانی لازم دارم، ولی هیچ کنترل ActiveX ای که این کار رو برام انجام بده وجود نداره و نمیشه یک Win32 API رو از توی اسکریپت بطور مستقیم فراخوانی کرد، میتونی تابع ChangeLightBulbWindowHandlerEx رو به امکانات داخلی VBScript اضافه کنی؟ احتمالا بیشتر از پنج خط کد نمیشه!»

من همیشه به این افراد یک جواب رو میدم -- اگه فقط پنج خط کد میشه، پس خودت برو اون ActiveX Object رو بنویس. بله، چون حق با توئه، احتمالا بیشتر از پنج دقیقه برای اضافه کردن اون ویژگی به کتابخانه VBScript Runtime طول نمی کشه. اما واقعا چند تا کارمند مایکروسافت لازمه که یک لامپ عوض بشه؟

  • یک برنامه نویس برای این که پنج دقیقه ای ChangeLightBulbWindowHandleEx رو پیاده سازی کنه.
  • یک مدیر برنامه برای نوشتن مشخصات [این قابلیت جدید].
  • یک متخصص محلی سازی برای برسی مسائلی که هنگام محلی سازی مشخصات ممکنه پیش بیاد.
  • یک متخصص کارایی برای برسی مشخصات [مذکور] جهت کارامدی و استفاده [آسان و] مناسب.
  • حداقل یک برنامه نویس، آزمایش کننده و مدیر برنامه برای برسی (به روش طوفان ذهنی) آسیب پذیری امنیتی احتمالی.
  • یک مدیر برنامه برای اضافه کردن مدل امنیتی به مشخصات [مذکور]
  • یک آزمایش گر، برای نوشتن طرح های آزمون.
  • یک مدیر آزمون برای به روز رسانی زمانبندی آزمون [واحد].
  • یک آزمایش کننده برای نوشتن موارد آزمایش و اضافه کردن آن به اتوماسیون [آزمایش] شبانه.
  • سه یا چهار آزمایش کننده برای مشارکت در خطایابی به هم ریخته به روش ad hoc.
  • یک نویسنده فنی برای نوشتن مستندات.
  • یک بازبین فنی برای [بازبینی و] ویرایش مستندات.
  • یک ویرایش گر رونوشت برای [بازبینی و] ویرایش مستندات.
  • یک مدیر مستندات برای جایگذاری مستندات جدید در متن مستندات موجود، به روز رسانی جدول ها، شاخص ها و غیره...

بیست و پنج مترجم جهت ترجمه مستندات و پیام های خطا برای تمامی زبان هایی که توسط ویندوز پشتیبانی می شود. مدیران مترجم ها در ایرلند (مترجم های زبان های اروپایی) و ژاپن (زبان های آسیایی) زندگی می کنند، که چندین ساعت اختلاف زمانی نسبت به ردموند (آمریکا) دارند که [توجیه و] هماهنگی با آن ها می تواند یک مسئله پیچیده باشد.

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

هیچ کدام از این موارد بطور مستقل زیاد طول نمیکشه، اما روی هم رفته برای این قابلیت ساده زیادن. احتمالا دقت کردین که من همه مواردی که Joe دربارش صحبت کرده بود رو اضافه نکردم. مثلا اگه یه bug توی اون پنج خط کد بود چی؟ همون پنج دقیقه زمان برای توسعه (نوشتن کد) تبدیل به چند نفر-هفته کار میشه و هزینه هنگفتی داره، همش بخاطر اینکه در زمان چند دقیقه ای یک نفر (برنامه نویس مشتری) صرفه جویی بشه که می خواد یک کنترل VB6 کاری که اون می خواد بکنه! متاسفم، ولی این هیچ ارزش (سود) تجاری نداره. ما، در مایکروسافت، به سختی تلاش می کنیم تا یک نرم افزار ناقص منتشر نشه. برای یک نرم افزار خوب، با حساب چیزهای دیگه، اطمینان از اینکه یک نابینای کاتالانی که اسپانیولی صحبت می کنه، می تونه به سادگی از این قابلیت استفاده کنه، بدون اینکه نگران معرفی یک آسیب پذیری جدید بشه، نسبتا مشکله! اما ما باید این کار رو انجام بدیم، چون وقتی یه نسخه جدید از موتورهای اسکریپتی رو بیرون میدیم، صدها میلیون نفر اون کد رو امتحان می کنن و ده ها میلیون نفر باهاش برنامه می نویسن.

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

البته، KC Lemson، Raymond Chen و Chris Pratley نظراتی روی این موضوع دارند.

منبع

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

ویژگی‌های جدید در C# 6 - بخش دوم

در صورتی که بخش اول این مجموعه را مطالعه نکرده‌اید، پیشنهاد می‌کنم ابتدا بخش اول را مطالعه کنید:

ویژگی‌های جدید در C# 6 - بخش اول

ادامه بحث:

۵. فیلترکردن Exceptionها

این امکان در VB و #F موجود بوده است. همکنون این ویژگی برای #C نیز اضافه شده است:

try { … }
catch (MyException e) if (myfilter(e))
{
        //…
}

در صورتی که عبارت داخل پرانتز به true ارزیابی شود، بلوک catch اجرا خواهد شد وگرنه Exception نادیده گرفته می‌شود.

یکی از کاربردهای آن می‌تواند زمان log کردن خطا باشد. به این صورت که در صورتی که خطا log شده بودن بخش catch اجرا شود. می‌توان این سناریو را خودکار کرد:

private static bool Log(Exception e) { /* اطلاعات را لاگ کنید */ ; return true; }
…
try { … } catch (Exception e) if (Log(e)) {}

۶. تعریف عبارت‌ها

گاهی تعریف متغیرها وقت‌گیراست و به شکل یک کاراضافه نمود پیدا می‌کند. یکی از مواقع هنگام استفاده از دستور TryParse است. با استفاده از قابلیت جدید C# می‌توان متغیرهای محلی را(با initializer یا بدون آن) وسط عبارات تعریف کرد. به مثال‌های زیر توجه کنید:

if (int.TryParse(s, out int i)) { … }
GetInfo(out var x, out var y);
Console.WriteLine("Result: {0}", (int x = GetValue()) * x); 
if ((string s = o as string) != null) { … s … }

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

۷. عملگرهای Null Conditional

گاهی نیاز است که بررسی‌هایی از جهت Null نبودن، روی کد انجام شود. عملگر Null-Conditional به شما این امکان را خواهد داد تا فقط زمانی به اعضای یک شی دسترسی داشته باشید که آن شی Null نباشد. در صورت Null بودن شی والد تنها یک نتیجه Null برگشت داده خواهد شد و نه یک Exception که موجب خطای زمان اجرا گردد:

int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null

همچنین می‌توان این عملگر را با عملگر ترکیبی Null بودن (C# (null coalescing operator همزمان استفاده کرد:

int length = customers?.Length ?? 0; // 0 if customers is null

عملگر Null Conditional عملیاتی مشابه اتصال کوتاه (Short Circuiting) را شبیه‌سازی می‌کند. به این‌صورت که یک زنجیره از اعضا و فراخوان‌های نوشته شده پس از علامت ؟ تنها زمانی اجرا می‌شوند که شی والد Null نباشد:

int? first = customers?[0].Orders.Count();

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

int? first = (customers != null) ? customers[0].Orders.Count() : null;

به غیر از شی customer که پیش از همه محاسبه می‌شود، هیچ‌کدام از اعضا، فراخوان‌هایی که بلافاصله پس از علامت ؟ آمده‌اند تا زمانی که شی customer، null باشد اجرا نخواهند شد.

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

int? first = customers?[0].Orders?.Count();

۸. استفاده از await در بلاک catch و finally

در C# 5 امکان استفاده از کلمه‌کلیدی await در بلاک catch و یا finally وجود نداشت همچنین به‌نظر می‌رسید امکان پیاده‌سازی آن نیز هیچ‌گاه وجود نداشته باشد. اما الان متوجه می‌شویم هیچ چیزی غیر ممکن نیست حتی خود غیرممکن (!):

Resource res = null;
try
{
       res = await Resource.OpenAsync(…); //قبلا این کد را می‌توانستیم فقط داشته باشیم
…
} 
catch(ResourceException e)
{
       await Resource.LogAsync(res, e); // همکنون می‌توان این کد را نوشت
}
finally
{
       if (res != null) await res.CloseAsync(); // و این کد را
}

کلیه مطالب ارائه شده در این دو پست براساس اطلاعات ارائه شده در وب جمع‌آوری شده است و تا پیش از ارائه رسمی C# 6 نمی‌توان با قاطعیت در مورد وجود و یا عدم وجود آنها در نگارش بعدی بحث کرد. حتی ممکن است برخی از این ویژگی‌ها با صلاحدید مایکروسافت تغییر کنند و یا به‌طور کاملا حذف شوند.

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

پیاده سازی گام به گام الگوی جنریک Repository در #C

اگر تا به‌حال چیزی به اسم الگوهای طراحی یا Design Patterns به‌گوش شما نخورده است پیشنهاد می‌کنم قبل از مطالعه این مقاله ابتدا یک ‌آشنایی نسبی با آن پیدا کنید.

دسترسی مستقیم به دیتابیس از طریق منطق تجاری برنامه (Business Logic) کار جالبی نیست. این کار توسعه و تست برنامه را مشکل خواهد کرد. دسترسی مستقیم به دیتابیس از طریق BL موجب بروز مشکلات زیر خواهد شد:

۱- آزمون واحد BL را پیچیده خواهد کرد.

۲- BL بدون وجود عناصر خارجی مانند دیتابیس قابل تست شدن نخواهد بود.

۳- بخش دسترسی به داده در سرتاسر BL تکرار خواهد شد.

بدون یک Repository یک برنامه به شکل زیر خواهد بود:

 

الگوی Repository منطق دستیابی به داده را جدا و آن را به موجودیت‌های داخل BL نگاشت می‌نماید. اینکار باعث می‌شود هم با موجودیت‌های دامنه کار کند و هم منطق دستیابی به داده را اجرا نماید. در الگوی Repository، موجودیت‌های دامنه، منطق دستیابی به داده و منطق تجاری برنامه (BL) با یکدیگر با استفاده از واسط‌(interface)ها ارتباط برقرار می‌کنند.

در این‌حالت جزئیات دستیابی به داده از BL مخفی می‌ماند. به عبارت دیگر BL می‌تواند بدون داشتن هرگونه دانشی از معماری دستیابی به داده مورد استفاده در برنامه به شی داده‌ دسترسی داشته باشد. به‌عنوان مثال در الگوی Repository، BL اطلاع ندارد که آیا برنامه از LINQ to SQL استفاده می‌کند یا ADO.NET Entity Model ORM. این کار یک مزیت مهم دارد:معماری یا منبع داده‌ای مورد استفاده می‌تواند بدون ایجاد کوچکترین تاثیری روی BL تغییر کند.

 

برخی از سایر فواید استفاده از الگوی Repository عبارت‌است از:

        • منطق تجاری(BL) برنامه می‌تواند بدون نیاز به یک منبع خارجی تست شود.

        • منطق دسترسی به دیتابیس (DAL) برنامه می‌تواند به‌طور جداگانه تست شود.

        • دیگر کد تکراری وجود نخواهد داشت.

        • استراتژی کش نمودن داده برای منبع داده‌ای می‌تواند متمرکز گردد.

        • توسعه دامنه‌محور(Domain Driven) آسان‌تر خواهد بود.

        • متمرکز شدن DAL ، بنابراین نگهداری کد آسان‌تر خواهد شد.

حالا وقت آن رسیده است که الگوی Repository را در#C پیاده کنیم. برای اینکار ما با ایجاد یک کلاس Entity، کار را شروع خواهیم کرد. این کلاس شامل یک متغیر سراسری Id خواهد بود که بیانگر ستون Identity موجودیت ما است.

public class IEntity
    {
        public string Id; 
    }

همچنین interface جنریک Repository نوع IEntity می‌تواند به شکل زیر باشد. همانطور که مشاهده می‌کنید عملیات CRUD بخشی از آن است. توجه کنید که درصورتی که یک Repository به‌خصوص نیازمند عملیات اضافی باشد، آن عملیات می‌تواند در واسط جنریک Repository تعبیه گردد.

public interface IRepository<T> where T: IEntity
    {

        IEnumerable<T> List { get; }
        void Add(T entity);
        void Delete(T entity);
        void Update(T entity);
        T FindById(int Id);
    }

فرض کنید می‌خواهیم با یک کلاس مولف(Author) کار کنیم. برای این‌کار یک کلاس موجودیت Author را ایجاد می‌کنیم. این کلاس باید از کلاس IEntity مشتق شود تا بتواند با الگوی جنریک Repository کار کند:

    [Table("Author")]
    public partial class Author : IEntity
    {
        public int Id { get; set; }

        [Required]
        public string authorname { get; set; }
    }

همانطور که ملاحظه می‌کنید کلاس به صفت Table آراسته شده است. در اینجا تفاوتی نمی‌کند که شما از این روش استفاده کنید یا از Fluent API.

برای ایجاد نمودن AuthorRepository یک کلاس ایجاد خواهیم کرد که اینترفیسRepository جنریک ،<IRepository<Author را پیاده سازی خواهد کرد. در این مثال ما عملیات CRUD را توسط Entity Framework انجام داده‌ایم. شما می‌توانید این عملیات را توسط LINQ to SQL، ADO.NET یا هر روش دلخواه دیگری انجام دهید.

در مورد انجام عملیات CRUD در کلاس AuthorRepository نکته‌ی خاصی وجود ندارد و این بخش شامل کدهای ساده LINQ to Entity برای اجرای عملیات CRUD‌ است.

کلاس AuthorRepository به شکل زیر است:

public class AuthorRepository : IRepository<Author>
    {

        MyModel _authorContext;

        public AuthorRepository()
        {
            _authorContext = new MyModel();

        }
        public IEnumerable<Author> List
        {
            get
            {
                return _authorContext.Authors;
            }
            
        }

        public void Add(Author entity)
        {
            _authorContext.Authors.Add(entity);
            _authorContext.SaveChanges();
        }

        public void Delete(Author entity)
        {
            _authorContext.Authors.Remove(entity);
            _authorContext.SaveChanges();
        }

        public void Update(Author entity)
        {
            _authorContext.Entry(entity).State = System.Data.Entity.EntityState.Modified;
            _authorContext.SaveChanges();
            
        }

        public Author FindById(int Id)
        {
            var result = (from r in _authorContext.Authors where r.Id == Id select r).FirstOrDefault();
            return result; 
        }

این تمام کاری است که باید برای پیاده‌سازی الگوی جنریک Repository انجام دهید. در هرنوع برنامه خواه MVC، خواه WPF یا یک Console Application ساده، نحوه استفاده از یک الگوی جنریک Repository به شکل زیر خواهد بود:

IRepository<Author> repository = new AuthorRepository();
            var result = repository.List;
            foreach (var r in result)
            {
                Console.WriteLine(r.authorname);

            }

در اینجا من مستقیما یک نمونه از کلاس AuthorRepository ایجاد کردم. برای تست‌پذیری بهتر و ایجاد Dependency زمان اجرا می‌توان از ابزارهای Dependency Injection‌ی مثل StructureMap و یا Unity برای ایجاد یک نمونه از شی AuthorRepository استفاده کنید.

 

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

ویژگی‌های جدید در C# 6 - بخش اول

C# 6 قرار است همراه با Visual Studio 2014 عرضه شود. مطابق معمول مایکروسافت ویژگی‌هایی را در این نسخه به کامپایلر و زبان#C اضافه نموده که برخی از کاربردی‌ترین این ویژگی‌ها در زیر آمده است:

۱. بهبود پراپرتی‌ها

۱-۱. ایجاد  Initializerبرای پراپرتی‌های خودکار

public class Customer
{
    public string First { get; set; } = "Mohsen";
    public string Last { get; set; } = "Ali";
}

Initializerها مستقیما فیلدهای مخفی ایجاد شده توسط کامپایلر را مقدار دهی می‌کنند. Initializer به ترتیب نوشتاری‌شان اجرا می‌شوند.

۲-۱. پراپرتی‌های فقط خواندنی

می‌توان یک پراپرتی با مقداردهی‌اولیه فقط خواندنی ایجاد کرد:

public class Customer
{
    public string First { get; } = "Mohsen";
    public string Last { get; } = "Ali";
}

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

public class Customer
{
    public string Name { get; };
    public Customer(string first, string last)
    {
         Name = first + " " + last;
    }
}

۲. سازنده‌های اولیه (Primary Constructors)

با استفاده از سازنده‌های اولیه می‌توان کلاس‌هایی با پارامترهای سازنده تعریف کرد بدون آنکه نیاز به تعریف سازنده داشته باشیم.

۱-۲. پارامترها در classها و structها

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

public class Customer(string first, string last)
{
    public string First { get; } = first;
    public string Last { get; } = last;
}

۲-۲. بدنه‌ی کد سازنده‌های اولیه

هرچند ارسال پارامترها در روش بیان شده ساده‌تر از روش‌ پیشین در#C است اما بدون نوشتن کد در داخل بدنه سازنده این ویژگی چندان کارایی نخواهد داشت. برای این منظور در C# 6 نوشتن بدنه‌ی سازنده نیز از طریق ایجاد دو آکولاد در داخل کلاس امکان پذیر است:

public class Customer(string first, string last)
{
    {
       if (first == null) throw new ArgumentNullException("first");
       if (last == null) throw new ArgumentNullException("last");
    }
    public string First { get; } = first;
    public string Last { get; } = last;
}

۳-۲. سازنده‌های صریح (Explicit)

یک کلاس تعریف شده با یک سازنده اولیه می‌تواند سازنده‌های دیگری را نیز داشته باشد (همان سازنده‌های صریح پیشین). اما برای اطمینان از اینکه پارامترهای سازنده اولیه مقداردهی می‌شوند باید همه‌ی سازنده‌های دیگر عبارت ()this را صدا بزنند:

public Point() : this(0, 0) {} // سازنده اولیه را فراخوانی می‌کند

سازنده‌های صریح مانند قبل می‌توانند یکدیگر را فراخوانی کنند ولی به‌طور مستقیم یا غیرمستقیم سازنده اولیه را فراخوانی ‌می‌کنند. (مثل زمانی که یک سازنده ()base را فراخوانی می‌کند).

۴-۲ راه‌انداز‌های Base

یک سازنده‌ اولیه به صورت صریح یا غیر صریح، همیشه یک راه‌انداز base را فراخوانی می‌کند. در صورتی که را‌ه‌انداز base ی تعیین نشده باشد، درست مثل بقیه سازنده‌ها یک سازنده base بدون پارامتر پیش‌فرض را فراخوانی ‌میکند.

روش فراخوانی صریح راه‌انداز‌ base این است که یک آرگومان به یک کلاس base ارسال کنیم:

class BufferFullException() : Exception("Buffer full") { … }

۳. استفاده از Expression در اعضای متدها

۱-۳. متدها

متدها می‌توانند با استفاده از عبارات Lambda بدنه خود را تکمیل کنند:

public Point Move(int dx, int dy) => new Point(x + dx, y + dy); 

در صورتی که خروجی متد void باشد، عبارت پس از پیکان باید یک عبارت باشد:

public void Print() => Console.WriteLine(First + " " + Last);

۲-۳ پراپرتی‌ها و ایندکسرها

برای استفاده از عبارات lambda در پراپرتی‌ها و ایندکسرها باید آنها فقط خواندنی باشند و بدنه آنها توسط عبارات lambda مقدار دهی شده باشد:

public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id); 

توجه کنید که در اینجا از get استفاده‌ای نشده است و به صورت ضمنی در syntax عبارت موجود است.

۴. تعریف کلاس‌های static در بخش using و استفاده از اعضای آنها 

با استفاده از این ویژگی می‌توان کلاس‌های static را در بخش using معرفی و از تمام اعضای static آنها بدون ذکر نام کلاس بهره‌برد. کلاس System.Math یک نمونه‌ی پرکاربرد این مورد است:

using System.Console;
using System.Math;
class Program
{
   static void Main()
   {
      WriteLine(Sqrt(3*3 + 4*4)); 
   }
}
  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

مفهوم Delegateها در #C

Delegate یک نوع ارجاعی است که reference از یک متد را نگهداری می‌کند. هر متدی که دارای امضای مشابه با امضای Delegateها داشته باشد می‌تواند به یک Delegate منتسب شود.

Delegate ها بسیار مشابه به اشاره‌گر به توابع در زبان‌هایی مانند ++C هستند، با این تفاوت که Delegateها نوع-امن هستند و تحت نظارت مستقیم کامپایلر در دات نت تعریف و اجرا می‌شوند.

می‌توان گفت Delegateها پیاده‌سازی شی‌گرایی از اشاره‌گر به توابع هستند.

سه مرحله اصلی برای تعریف و استفاده از Delegateها وجود دارد:

۱. تعریف Delegate

برای تعریف Delegate از واژه کلیدی delegate استفاده می‌شود:

public delegate void MyDelagate(int a, int b);

۲. نمونه سازی از Delegate

برای ایجاد یک نمونه از Delegateها باید یک متد با امضای یکسان با Delegate معرفی شده را به آن انتساب داد:

MyDelagate sum = new MyDelagate(یک نمونه متد با امضای معتبر);

۳. فراخوانی Delegate

فراخوانی یک Delegate مشابه فراخوانی ساده‌ی یک متد است:

 

Console.WriteLine("Sum of two integer is = " + sum(2, 20));

 

به کدهای ذیل توجه کنید:

public delegate void MyDelagate(int a, int b);
public class Example
    {
        //  انتساب داده شود delegate متدی که قرار است به
        public void Sum(int a, int b)
        {
            Console.WriteLine("Sum of integers is = " + (a + b));
        }
        // انتساب داده شود delegate متدی که قرار است به
        public void Difference(int a, int b)
        {
            Console.WriteLine("Difference of integer is = " + (a - b));
        }
    }

 class Program
    {
        static void Main(string[] args)
        {
            var example = new Example();
            var sum = new MyDelagate(example.Sum);
            var dif = new MyDelagate(example.Difference);

            sum(20, 12);
            dif(20, 12);

            Console.ReadKey();
        }
    }

و در خروجی داریم:

/*

Sum of two integer is = 32
Difference of two integer is = 8

*/

ماهیت وجودی Delegateها:

- Delegateها باعث می‌شوند تا بتوانیم متدها را به صورت پارامتر ارسال کنیم (یکی از وظایف مهم آن‌ها این است که ‌می‌توان توسط آنها پیاده ‌سازی یک متد را، به‌عهده‌ی توسعه‌دهنده‌ی نهایی مصرف‌‌کننده از کد یا اسمبلی ما گذاشت).

- Delegateها در هنگام استفاده از روال‌های انجام رخدادها (Event handling) مورد استفاده قرار می‌گیرند.

- Delegateها می‌توانند به‌یکدیگر متصل شوند، این قابلیت اجازه می‌دهد تا یک مجموعه متد به عنوان یک واحد مجزا اجرا شود.

- زمانی که یک Delegate ایجاد می‌شود، متد انتساب داده شده به آن هرگز تغییری نخواهد کرد، این به‌دلیل ماهیت تغییرناپذیر Delegateها است.

- Delegateها روشی را برای اجرای متدها در زمان اجرا فراهم می‌کنند.

- همه‌ی Delegateها از کلاس System.MulticastDelegate مشتق می‌شوند که خود آن از کلاس System.Delegate مشتق می‌شود.

- نوع‌های Delegateهای ایجاد شده با یکدیگر یکسان نیستند، حتی اگر دارای امضای یکسانی باشند. تنها زمانی دارای نوع یکسانی هستند که به یک متد تعریفی یکسان reference داده شده باشند. (هر دو از یک تعریف Delegate منشعب شده باشند!)

اگر تعریف Delegateی به شکل زیر داشته باشیم:

 public delegate void MyDelagate(int a, int b);
 public delegate void MyDelagate2(int a, int b);

قطعه کد زیر با اینکه در آن Delegateها دارای امضای یکسانی هستند باعث ایجاد خطای

'Cannot implicitly convert type 'ConsoleApplication.MyDelagate2' to 'ConsoleApplication.MyDelagate خواهد شد:

 var example = new Example();
 var sum = new MyDelagate(example.Sum);
 sum = new MyDelagate2(example.Difference); //خطای کامپایلر

 

انواع Delegateها:

۱. Delegateهای Single cast

این نوع Delegateها فقط reference یک متد تکی را نگه می‌دارند. مثال‌های بالا همگی چگونگی تعریف این نوع Delegate را نشان می‌دهند.

۲.Delegateهای Multi cast

Delegateی که reference مربوط به بیشتر از یک متد را نگه‌داری می‌کند، Multi cast نامیده می‌شود. یک Delegate از این نوع تنها شامل reference متدهایی است که نوع خروجی آنها void باشد.

در اینجا از عملگرهای + و += برای ترکیب نمونه‌های ایجاد شده از Delegateها استفاده می‌کنیم. Delegateهای Multi cast تنها زمانی باهم برابرند که با ترتیب یکسانی به متدهای تعریفی یکسانی reference شده باشند:

 public delegate void MyDelagate(int a, int b);
    
    public class Example
    {
        //  انتساب داده شود delegate متدی که قرار است به
        public void Sum(int a, int b)
        {
            Console.WriteLine("Sum of integers is = " + (a + b));
        }
        // انتساب داده شود delegate متدی که قرار است به
        public void Difference(int a, int b)
        {
            Console.WriteLine("Difference of integer is = " + (a - b));
        }
    }

 class Program
    {
        static void Main(string[] args)
        {
            var example = new Example();
            var dgt = new MyDelagate(example.Sum);

            //Delegate انتساب یک متد دیگر به 
            dgt += new MyDelagate(example.Difference);
            dgt(20, 19);

            Console.ReadKey();
        }
    }

و خروجی در نهایت به شکل زیر خواهد بود:

/*

 Sum of integers is = 39 
 Difference of integer is = 1

*/
  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print

تفاوت بین Select و SelectMany در LINQ

عملگر Select و SelectMany هر دو جزء عملگرهای Projection هستند. عملگر Select برای انتخاب مقادیر از یک شی Collection استفاده می‌شود و از SelectMany زمانی که قصد داریم از Collection های تودرتو ( Collectionی از Collectionها) مقادیری را استخراج کنیم استفاده می‌شود.

عملگر Select یک مجموعه قابل شمارش را به ازای هر منبع داده‌ای تولید می‌کند در صورتی که SelectMany یک خروجی تکی حاصل از الحاق منابع داده‌ای را برمی‌گرداند. در حقیقت SelectMany خروجی Listی از Listها را به‌یک List ساده تبدیل می‌کند.

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

class Employee
    {
        public string Name { get; set; }
        public List<string> Skills { get; set; }
    }

static void Main(string[] args)
        {
            List<Employee> employees = new List<Employee>();
            Employee emp1 = new Employee { Name = "Mohsen", Skills = new List<string> { "C", "C++", "Java" } };
            Employee emp2 = new Employee { Name = "Reza", Skills = new List<string> { "SQL Server", "C#", "ASP.NET" } };

            Employee emp3 = new Employee { Name = "Ali", Skills = new List<string> { "C#", "ASP.NET MVC", "Windows Azure", "SQL Server" } };

            employees.Add(emp1);
            employees.Add(emp2);
            employees.Add(emp3);

            // از طریق عملگر
            //Select()
            IEnumerable<List<String>> resultSelect = employees.Select(e => e.Skills);

            Console.WriteLine("**************** Select ******************");

            //به دو حلقه نیاز داریم چون کوئری لیستی از لیست‌ها را بر‌می‌گرداند
            foreach (List<String> skillList in resultSelect)
            {
                foreach (string skill in skillList)
                {
                    Console.WriteLine(skill);
                }
                Console.WriteLine();
            }

            // از طریق عملگر
            // SelectMany()
            IEnumerable<string> resultSelectMany = employees.SelectMany(emp => emp.Skills);

            Console.WriteLine("**************** SelectMany ******************");

            //  فقط یک حلقه نیاز است چون کوئری یک لیست قابل شمارش را برگردانده است
            foreach (string skill in resultSelectMany)
            {
                Console.WriteLine(skill);
            }

            Console.ReadKey();

        }

در نهایت خروجی به شکل زیر خواهد بود ( به فواصل جداکننده هر لیست در خروجی دقت کنید):

/*
**************** Select ******************
 

C
C++
Java
 
SQL Server
C#
ASP.NET
 
C#
ASP.NET MVC
Windows Azure
SQL Server
 
**************** SelectMany ******************
 
C
C++
Java
SQL Server
C#
ASP.NET
C#
ASP.NET MVC
Windows Azure
SQL Server


*/

 

 

 

  • Book.mark.hu
  • co.mments
  • De.lirio.us
  • del.icio.us
  • Digg
  • DotNetKicks
  • E-Mail
  • Facebook
  • feedmelinks
  • Google
  • LinkedIn
  • msdn Social
  • MyShare
  • Slashdot
  • StumbleUpon
  • TwitThis
  • Tumblr
  • Yahoo! Buzz
  • Yahoo! MyWeb
  • Print