نظرات مطالب
EF Code First #12
در صورتی که بخواهیم Context را به ازای هر ویندوز فرم زنده نگه داریم در WinForm، پیاده سازی زیر صحیح است:
static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Database.SetInitializer<LoanContext>(null);

            // تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود
            ObjectFactory.Initialize(x =>
            {
                x.For<IUnitOfWork>().Use<LoanContext>();
                x.For<IEmployeeService>().Use<EmployeeService>();
            });

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmMain());
        }
    }
و در frmMain به شکل زیر پیاده سازی را انجام دهیم:
 public partial class frmMain : Form
    {
        private IContainer _container;
        private IUnitOfWork _uow;

        public frmMain()
        {
            InitializeComponent();

            _container = ObjectFactory.Container.GetNestedContainer();
            _uow = _container.GetInstance<IUnitOfWork>();
        }

        private void btnHomeLoanRequest_Click(object sender, System.EventArgs e)
        {
            var employeeService = _container.GetInstance<IEmployeeService>();
            .
            .
            .
            _uow.SaveChanges();
        }
        private void btnEditLoan_Click(object sender, System.EventArgs e)
        {
            var categoryService = container.GetInstance<ICategoryService>();
            .
            .
            .
            _uow.SaveChanges();
        }
مطالب
ایجاد چارت سازمانی تحت وب #1
برای ایجاد چارت سازمانی همواره از راههای دیگر استفاده میکردیم مثلا از تصویر و فایل PDF ، فلش و یا ...
این مورد همیشه باعث اذیت طراحان وب و برنامه نویسان تحت وب بود. با ظهور برخی امکانات در HTML5 که میتوانید توضیحات آن را در مطلب Canvas Reference - قسمت اول سایت جاری مطالعه نمائید ، هم اکنون با استفاده از این امکانات و کتابخانه مربوط به ساخت نمودار سازمانی میتوانید مانند شکل ذیل نمودار در وب ایجاد نمائید.

نمودار سازمانی

برای اینکار ابتدا یک صفحه index.html ایجاد نموده و در قسمت body آن یک المنت از نوع canvas ایجاد نمائید:

<canvas id="canvas1" width="800" height="800" ></canvas>
سپس فایلهای مورد نیاز را در قسمت head آن ارجاع نمائید:
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" >
<!--[if ie]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
<script type="text/javascript" src="orgchart.js"></script>
حال در انتهای متن فایل html این کد را قرار دهید :
var o = new orgChart();

o.addNode(1, '', '', 'Root node');
o.addNode(2, 1, 'u', 'u-node 1');
o.addNode(3, 1, 'u', 'u-node 2');
o.addNode(4, 1, 'u', 'u-node 3');
o.addNode(5, 1, 'l', 'l-node 1');
o.addNode(6, 1, 'l', 'l-node 2');
o.addNode(7, 1, 'r', 'r-node 1');
o.addNode(8, 1, 'r', 'r-node 2');
o.addNode(9, 1, 'r', 'r-node 3');

o.addNode('', '', '', 'Root 2');
o.addNode('', 'Root 2', 'r', 'using');
o.addNode('', 'Root 2', 'r', 'text as\nid');

o.drawChart('canvas1');
انواع نود در نمودار :
u -> نودهایی که در یک سطح افقی (کنار هم ) و در سطح زیرین یک پدر قرار میگیرند.
l -> نودهایی که در یک سطح عمودی ( زیر هم ) و در سمت چپ نود پدر قرار میگیرند.
r -> نوهایی که در یک سطح عمودی ( زیر هم ) و در سمت راست نود پدر قرار میگیرند.

پارامترهای نودها :
  1. شناسه نود است و میتواند عدد یا رشته باشد . در صورتی که خالی بماند متن نود بعنوان شناسه استفاده میشود.
  2. شناسه نود پدر است و در صورتی که خالی ( یا ناشناس ) باشد بعنوان نود اصلی ( پدر ) نمایش داده میشود.
  3. نوع اتصال نودهای r , l , u . برای نود پدر نادیده گرفته میشود.
  4. متن نود . استفاده از "n\"  جلمه را شکسته و به خط جدید منتقل میکند.
  5. نود با نشانه مشخص ( اگر 1 باشد ، حاشیه با ضخامت کشیده میشود. ( اختیاری )
  6. آدرس یک نود - اختصاص آدرس url  جهت اضافه کردن آن به یک نود ( اختیاری )
  7. رنگ خط حاشیه ( اختیاری )
  8. رنگ پس زمینه ( اختیاری )
  9. رنگ متن و فونت ( اختیاری )

پارامترهای تابع ()drowChart :

  1. شناسه المنت canvas
  2. تراز کردن نمودار با استفاده از حرف 'c' یا کلمه 'center' . در صورت حذف ، نمودار در سمت چپ صفحه نمایش داده خواهد شد. تراز چپ ( اختیاری )
  3. تناسب اندازه canvas .  اگر true باشد canvas به اندازه نمودار چارت ، تغییر اندازه میدهد . (اختیاری)
مطمئن باشید که فایل index.html , excanvas.js  ,orgchart.js  در یک فولدر قرار گرفته باشند .
در مطلب بعدی نمایش با رنگهای مختلف ارائه خواهد شد.

مورد نیازهای مطلب جاری :
  1. excanvas.js
  2. orgchart.js
  3. index.html
اشتراک‌ها
دلیل استفاده از Linq بجای Hql و Criteria

در این مطلب کوتاه مقایسه ای شده بین استفاده از Linq ، HQL  و Criteria در NHibernate ، و با دلیل استفاده از Linq پیشنهاد می‌شود

دلیل استفاده از Linq بجای Hql  و Criteria
مطالب
OpenCVSharp #15
تشخیص چهره به کمک OpenCV

OpenCV به کمک الگوریتم‌های machine learning (در اینجا Haar feature-based cascade classifiers) و داد‌ه‌های مرتبط با آن‌ها، قادر است اشیاء پیچیده‌ای را در تصاویر پیدا کند. برای پیگیری مثال بحث جاری نیاز است کتابخانه‌ی اصلی OpenCV را دریافت کنید؛ از این جهت که به فایل‌های XML موجود در پوشه‌ی opencv\sources\data\haarcascades آن نیاز داریم. در اینجا از دو فایل haarcascade_eye_tree_eyeglasses.xml و haarcascade_frontalface_alt.xml آن استفاده خواهیم کرد (این دوفایل جهت سهولت کار، به همراه مثال این بحث نیز ارائه شده‌اند).
فایل haarcascade_frontalface_alt.xml اصطلاحا trained data مخصوص یافتن چهره‌ی انسان در تصاویر است و فایل haarcascade_eye_tree_eyeglasses.xml کمک می‌کند تا بتوان در چهره‌ی یافت شده، چشمان شخص را نیز با دقت بالایی تشخیص داد؛ چیزی همانند تصویر ذیل:



مراحل تشخیص چهره توسط OpenCVSharp

ابتدا همانند سایر مثال‌های OpenCV، تصویر مدنظر را به کمک کلاس Mat بارگذاری می‌کنیم:
var srcImage = new Mat(@"..\..\Images\Test.jpg");
Cv2.ImShow("Source", srcImage);
Cv2.WaitKey(1); // do events
 
var grayImage = new Mat();
Cv2.CvtColor(srcImage, grayImage, ColorConversion.BgrToGray);
Cv2.EqualizeHist(grayImage, grayImage);
همچنین در اینجا جهت بالا رفتن سرعت کار و بهبود دقت تشخیص چهره، این تصویر اصلی به یک تصویر سیاه و سفید تبدیل شده‌است و سپس متد Cv2.EqualizeHist بر روی آن فراخوانی گشته‌است. این متد وضوح تصویر را جهت یافتن الگوها بهبود می‌بخشد.
سپس فایل xml یاد شده‌ی در ابتدای بحث را توسط کلاس CascadeClassifier بارگذاری می‌کنیم:
var cascade = new CascadeClassifier(@"..\..\Data\haarcascade_frontalface_alt.xml");
var nestedCascade = new CascadeClassifier(@"..\..\Data\haarcascade_eye_tree_eyeglasses.xml");
 
var faces = cascade.DetectMultiScale(
    image: grayImage,
    scaleFactor: 1.1,
    minNeighbors: 2,
    flags: HaarDetectionType.Zero | HaarDetectionType.ScaleImage,
    minSize: new Size(30, 30)
    );
 
Console.WriteLine("Detected faces: {0}", faces.Length);
پس از بارگذاری فایل‌های XML اطلاعات نحوه‌ی تشخیص چهره و اعضای آن، با فراخوانی متد DetectMultiScale، کار تشخیص چهره و استخراج آن از grayImage انجام خواهد شد. در اینجا minSize، اندازه‌ی حداقل چهره‌ی مدنظر است که قرار هست تشخیص داده شود. نواحی کوچکتر از این اندازه، به عنوان نویز در نظر گرفته خواهند شد و پردازش نمی‌شوند.
خروجی این متد، مستطیل‌ها و نواحی یافت شده‌ی مرتبط با چهره‌های موجود در تصویر هستند. اکنون می‌توان حلقه‌ای را تشکیل داد و این نواحی را برای مثال با مستطیل‌های رنگی، متمایز کرد:
var rnd = new Random();
var count = 1;
foreach (var faceRect in faces)
{
    var detectedFaceImage = new Mat(srcImage, faceRect);
    Cv2.ImShow(string.Format("Face {0}", count), detectedFaceImage);
    Cv2.WaitKey(1); // do events
 
    var color = Scalar.FromRgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
    Cv2.Rectangle(srcImage, faceRect, color, 3);
  
    count++;
}
 
Cv2.ImShow("Haar Detection", srcImage);
Cv2.WaitKey(1); // do events
در اینجا علاوه بر رسم یک مستطیل، به دور ناحیه‌ی تشخیص داده شده، نحوه‌ی استخراج تصویر آن ناحیه را هم در سطر var detectedFaceImage مشاهده می‌کنید.

همچنین اگر علاقمند باشیم تا در این ناحیه‌ی یافت شده، چشمان شخص را نیز استخراج کنیم، می‌توان به نحو ذیل عمل کرد:
var rnd = new Random();
var count = 1;
foreach (var faceRect in faces)
{
    var detectedFaceImage = new Mat(srcImage, faceRect);
    Cv2.ImShow(string.Format("Face {0}", count), detectedFaceImage);
    Cv2.WaitKey(1); // do events
 
    var color = Scalar.FromRgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
    Cv2.Rectangle(srcImage, faceRect, color, 3);
 
 
    var detectedFaceGrayImage = new Mat();
    Cv2.CvtColor(detectedFaceImage, detectedFaceGrayImage, ColorConversion.BgrToGray);
    var nestedObjects = nestedCascade.DetectMultiScale(
        image: detectedFaceGrayImage,
        scaleFactor: 1.1,
        minNeighbors: 2,
        flags: HaarDetectionType.Zero | HaarDetectionType.ScaleImage,
        minSize: new Size(30, 30)
        );
 
    Console.WriteLine("Nested Objects[{0}]: {1}", count, nestedObjects.Length);
 
    foreach (var nestedObject in nestedObjects)
    {
        var center = new Point
        {
            X = Cv.Round(nestedObject.X + nestedObject.Width * 0.5) + faceRect.Left,
            Y = Cv.Round(nestedObject.Y + nestedObject.Height * 0.5) + faceRect.Top
        };
        var radius = Cv.Round((nestedObject.Width + nestedObject.Height) * 0.25);
        Cv2.Circle(srcImage, center, radius, color, thickness: 3);
    }
 
    count++;
}
 
Cv2.ImShow("Haar Detection", srcImage);
Cv2.WaitKey(1); // do events
کدهای ابتدایی آن همانند توضیحات قبل است. تنها تفاوت آن، استفاده از nestedCascade بارگذاری شده‌ی در ابتدای بحث می‌باشد. این nestedCascade حاوی trained data استخراج چشمان اشخاص، از تصاویر است. پارامتر ورودی آن‌را نیز تصویر سیاه و سفید ناحیه‌ی چهره‌ی یافت شده‌، قرار داده‌ایم تا سرعت تشخیص چشمان شخص، افزایش یابد.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مسیرراه‌ها
ASP.NET MVC
              پاسخ به بازخورد‌های پروژه‌ها
              اعمال شرط روی ردیف
              یک رخداد جدید به نام ShouldSkipRow به مجموعه رخدادهای موجود اضافه شد. (در SVN موجود است)
              events.ShouldSkipRow(args =>
              {
                  var rowData = args.TableRowData;
                  //var previousTableRowData = args.PreviousTableRowData;
               
                  var description = rowData.FirstOrDefault(x => x.PropertyName == "Description");
                  if (description != null &&
                      description.PropertyValue.ToSafeString() == "Description Description ... 1")
                  {
                      return true;
                  }
               
                  return false;
              });
              مطالب
              نمایش تعداد کل صفحات در iTextSharp

              در مورد نحوه‌ی نمایش شماره صفحه جاری در مثلا header یک گزارش PDF تهیه شده به کمک writer.PageNumber و ارث بری از کلاس PdfPageEventHelper،‌ در پایان مطلب فارسی نویسی در iTextSharp توضیح داده شد. این مورد جزو ضروریات یک گزارش خوب است، اما عموما نیاز است تا تعداد کل صفحات هم نمایش داده شود. مثلا صفحه n از 100 جایی در تمام صفحات درج شود و ... هیچ خاصیتی به نام TotalNumberOfPages را در این کتابخانه نمی‌توان یافت. علت هم این است که تعداد واقعی کل صفحات فقط در حین بسته شدن شیء Document مشخص می‌شود و نه در هنگام تهیه صفحات. بنابراین نکته تهیه و نمایش تعداد صفحات، در iTextSharp به صورت خلاصه به شرح زیر است:
              الف) باید در همان کلاسی که از PdfPageEventHelper به ارث رسیده است، متد OnCloseDocument را تحریف (override) کرد. در اینجا به خاصیت writer.PageNumber دسترسی داریم و writer.PageNumber - 1 مساوی است با تعداد کل صفحات.
              ب) در مرحله بعد نیاز است تا این عدد را به نحوی به تمام صفحات تولید شده اضافه کنیم. این کار هم ساده است و مبتنی است بر بکارگیری یک PdfTemplate :
              • در متد تحریف شده‌ی OnOpenDocument ، یک قالب PDF ساده را تولید می‌کنیم (مثلا یک مستطیل کوچک خالی).
              • سپس در متد OnEndPage ، این قالب را به انتهای تمام صفحات در حال تولید اضافه خواهیم کرد.
              • زمانیکه متد OnCloseDocument فراخوانده شد، عدد تعداد کل صفحات را در این قالب که به تمام صفحات اضافه شده، درج خواهیم کرد. به این ترتیب این عدد به صورت خودکار در تمام صفحات نمایش داده خواهد شد.

              پیاده سازی این توضیحات را در ادامه ملاحظه خواهید کرد:
              using System;
              using System.IO;
              using iTextSharp.text;
              using iTextSharp.text.pdf;

              namespace iTextSharpTests
              {
              public class PdfWriterPageEvents : PdfPageEventHelper
              {
              PdfContentByte _pdfContentByte;
              // عدد نهایی تعداد کل صفحات را در این قالب قرار خواهیم داد
              PdfTemplate _template;
              BaseFont _baseFont;

              public override void OnOpenDocument(PdfWriter writer, Document document)
              {
              _baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
              _pdfContentByte = writer.DirectContent;
              _template = _pdfContentByte.CreateTemplate(50, 50);
              }

              public override void OnEndPage(PdfWriter writer, Document document)
              {
              base.OnEndPage(writer, document);
              String text = writer.PageNumber + "/";
              float len = _baseFont.GetWidthPoint(text, 8);
              Rectangle pageSize = document.PageSize;
              _pdfContentByte.SetRGBColorFill(100, 100, 100);
              _pdfContentByte.BeginText();
              _pdfContentByte.SetFontAndSize(_baseFont, 8);
              _pdfContentByte.SetTextMatrix(pageSize.GetLeft(40), pageSize.GetBottom(30));
              _pdfContentByte.ShowText(text);
              _pdfContentByte.EndText();
              //در پایان هر صفحه یک جای خالی را مخصوص تعداد کل صفحات رزرو خواهیم کرد
              _pdfContentByte.AddTemplate(_template, pageSize.GetLeft(40) + len, pageSize.GetBottom(30));
              }
              public override void OnCloseDocument(PdfWriter writer, Document document)
              {
              base.OnCloseDocument(writer, document);
              _template.BeginText();
              _template.SetFontAndSize(_baseFont, 8);
              _template.SetTextMatrix(0, 0);
              //درج تعداد کل صفحات در تمام قالب‌های اضافه شده
              _template.ShowText((writer.PageNumber - 1).ToString());
              _template.EndText();
              }
              }

              public class AddTotalNoPages
              {
              public static void CreateTestPdf()
              {
              using (var pdfDoc = new Document(PageSize.A4))
              {
              var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("tpn.pdf", FileMode.Create));
              pdfWriter.PageEvent = new PdfWriterPageEvents();
              pdfDoc.Open();


              pdfDoc.Add(new Phrase("Page1"));
              pdfDoc.NewPage();
              pdfDoc.Add(new Phrase("Page2"));
              pdfDoc.NewPage();
              pdfDoc.Add(new Phrase("Page3"));
              }
              }
              }
              }

              مطالب
              ساخت یک بلاگ ساده با Ember.js، قسمت پنجم
              مقدمات ساخت بلاگ مبتنی بر ember.js در قسمت قبل به پایان رسید. در این قسمت صرفا قصد داریم بجای استفاده از HTML 5 local storage از یک REST web service مانند یک ASP.NET Web API Controller و یا یک ASP.NET MVC Controller استفاده کنیم و اطلاعات نهایی را به سرور ارسال و یا از آن دریافت کنیم.


              تنظیم Ember data برای کار با سرور

              Ember data به صورت پیش فرض و در پشت صحنه با استفاده از Ajax برای کار با یک REST Web Service طراحی شده‌است و کلیه تبادلات آن نیز با فرمت JSON انجام می‌شود. بنابراین تمام کدهای سمت کاربر قسمت قبل نیز در این حالت کار خواهند کرد. تنها کاری که باید انجام شود، حذف تنظیمات ابتدایی آن برای کار با HTML 5 local storage است.
              برای این منظور ابتدا فایل index.html را گشوده و سپس مدخل localstorage_adapter.js را از آن حذف کنید:
               <!--<script src="Scripts/Libs/localstorage_adapter.js" type="text/javascript"></script>-->
              همچنین دیگر نیازی به store.js نیز نمی‌باشد:
               <!--<script src="Scripts/App/store.js" type="text/javascript"></script>-->

              اکنون برنامه را اجرا کنید، چنین پیام خطایی را مشاهده خواهید کرد:

              همانطور که عنوان شد، ember data به صورت پیش فرض با سرور کار می‌کند و در اینجا به صورت خودکار، یک درخواست Get را به آدرس http://localhost:25918/posts جهت دریافت آخرین مطالب ثبت شده، ارسال کرده‌است و چون هنوز وب سرویسی در برنامه تعریف نشده، با خطای 404 و یا یافت نشد، مواجه شده‌است.
              این درخواست نیز بر اساس تعاریف موجود در فایل Scripts\Routes\posts.js، به سرور ارسال شده‌است:
              Blogger.PostsRoute = Ember.Route.extend({
                  model: function () {
                      return this.store.find('post');
                  }
              });
              Ember data شبیه به یک ORM عمل می‌کند. تنظیمات ابتدایی آن‌را تغییر دهید، بدون نیازی به تغییر در کدهای اصلی برنامه، می‌تواند با یک منبع داده جدید کار کند.


              تغییر تنظیمات پیش فرض آغازین Ember data

              آدرس درخواستی http://localhost:25918/posts به این معنا است که کلیه درخواست‌ها، به همان آدرس و پورت ریشه‌ی اصلی سایت ارسال می‌شوند. اما اگر یک ASP.NET Web API Controller را تعریف کنیم، نیاز است این درخواست‌ها، برای مثال به آدرس api/posts ارسال شوند؛ بجای /posts.
              برای این منظور پوشه‌ی جدید Scripts\Adapters را ایجاد کرده و فایل web_api_adapter.js را با این محتوا به آن اضافه کنید:
               DS.RESTAdapter.reopen({
                    namespace: 'api'
              });
              سپس تعریف مدخل آن‌را نیز به فایل index.html اضافه نمائید:
               <script src="Scripts/Adapters/web_api_adapter.js" type="text/javascript"></script>
              تعریف فضای نام در اینجا سبب خواهد شد تا درخواست‌های جدید به آدرس api/posts ارسال شوند.


              تغییر تنظیمات پیش فرض ASP.NET Web API

              در سمت سرور، بنابر اصول نامگذاری خواص، نام‌ها با حروف بزرگ شروع می‌شوند:
              namespace EmberJS03.Models
              {
                  public class Post
                  {
                      public int Id { set; get; }
                      public string Title { set; get; }
                      public string Body { set; get; }
                  }
              }
              اما در سمت کاربر و کدهای اسکریپتی، عکس آن صادق است. به همین جهت نیاز است که CamelCasePropertyNamesContractResolver را در JSON.NET تنظیم کرد تا به صورت خودکار اطلاعات ارسالی به کلاینت‌ها را به صورت camel case تولید کند:
              using System;
              using System.Web.Http;
              using System.Web.Routing;
              using Newtonsoft.Json.Serialization;
               
              namespace EmberJS03
              {
                  public class Global : System.Web.HttpApplication
                  {
               
                      protected void Application_Start(object sender, EventArgs e)
                      {
                          RouteTable.Routes.MapHttpRoute(
                             name: "DefaultApi",
                             routeTemplate: "api/{controller}/{id}",
                             defaults: new { id = RouteParameter.Optional }
                             );
               
                          var settings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
                          settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                      }
                  }
              }


              نحوه‌ی صحیح بازگشت اطلاعات از یک ASP.NET Web API جهت استفاده در Ember data

              با تنظیمات فوق، اگر کنترلر جدیدی را به صورت ذیل جهت بازگشت لیست مطالب تهیه کنیم:
              namespace EmberJS03.Controllers
              {
                  public class PostsController : ApiController
                  {
                      public IEnumerable<Post> Get()
                      {
                          return DataSource.PostsList;
                      } 
                  }
              }
              با یک چنین خطایی در سمت کاربر مواجه خواهیم شد:
                WARNING: Encountered "0" in payload, but no model was found for model name "0" (resolved model name using DS.RESTSerializer.typeForRoot("0"))
              این خطا از آنجا ناشی می‌شود که Ember data، اطلاعات دریافتی از سرور را بر اساس قرارداد JSON API دریافت می‌کند. برای حل این مشکل راه‌حل‌های زیادی مطرح شده‌اند که تعدادی از آن‌ها را در لینک‌های زیر می‌توانید مطالعه کنید:
              http://jsonapi.codeplex.com
              https://github.com/xqiu/MVCSPAWithEmberjs
              https://github.com/rmichela/EmberDataAdapter
              https://github.com/MilkyWayJoe/Ember-WebAPI-Adapter
              http://blog.yodersolutions.com/using-ember-data-with-asp-net-web-api
              http://emadibrahim.com/2014/04/09/emberjs-and-asp-net-web-api-and-json-serialization

              و خلاصه‌ی آن‌ها به این صورت است:
              خروجی JSON تولیدی توسط ASP.NET Web API چنین شکلی را دارد:
              [
                {
                  Id: 1,
                  Title: 'First Post'
                }, {
                  Id: 2,
                  Title: 'Second Post'
                }
              ]
              اما Ember data نیاز به یک چنین خروجی دارد:
              {
                posts: [{
                  id: 1,
                  title: 'First Post'
                }, {
                  id: 2,
                  title: 'Second Post'
                }]
              }
              به عبارتی آرایه‌ی مطالب را از ریشه‌ی posts باید دریافت کند (مطابق فرمت JSON API). برای انجام اینکار یا از لینک‌های معرفی شده استفاده کنید و یا راه حل ساده‌ی ذیل هم پاسخگو است:
              using System.Web.Http;
              using EmberJS03.Models;
               
              namespace EmberJS03.Controllers
              {
                  public class PostsController : ApiController
                  {
                      public object Get()
                      {
                          return new { posts = DataSource.PostsList };
                      }
                  }
              }
              در اینجا ریشه‌ی posts را توسط یک anonymous object ایجاد کرده‌ایم.
              اکنون اگر برنامه را اجرا کنید، در صفحه‌ی اول آن، لیست عناوین مطالب را مشاهده خواهید کرد.


              تاثیر قرارداد JSON API در حین ارسال اطلاعات به سرور توسط Ember data

              در تکمیل کنترلرهای Web API مورد نیاز (کنترلرهای مطالب و نظرات)، نیاز به متدهای Post، Update و Delete هم خواهد بود. دقیقا فرامین ارسالی توسط Ember data توسط همین HTTP Verbs به سمت سرور ارسال می‌شوند. در این حالت اگر متد Post کنترلر نظرات را به این شکل طراحی کنیم:
               public HttpResponseMessage Post(Comment comment)
              کار نخواهد کرد؛ چون مطابق فرمت JSON API ارسالی توسط Ember data، یک چنین شیء JSON ایی را دریافت خواهیم کرد:
              {"comment":{"text":"data...","post":"3"}}
              بنابراین Ember data چه در حین دریافت اطلاعات از سرور و چه در زمان ارسال اطلاعات به آن، اشیاء جاوا اسکریپتی را در یک ریشه‌ی هم نام آن شیء قرار می‌دهد.
              برای پردازش آن، یا باید از راه حل‌های ثالث مطرح شده در ابتدای بحث استفاده کنید و یا می‌توان مطابق کدهای ذیل، کل اطلاعات JSON ارسالی را توسط کتابخانه‌ی JSON.NET نیز پردازش کرد:
              namespace EmberJS03.Controllers
              {
                  public class CommentsController : ApiController
                  {
                      public HttpResponseMessage Post(HttpRequestMessage requestMessage)
                      {
                          var jsonContent = requestMessage.Content.ReadAsStringAsync().Result;
                          // {"comment":{"text":"data...","post":"3"}}
                          var jObj = JObject.Parse(jsonContent);
                          var comment = jObj.SelectToken("comment", false).ToObject<Comment>();
              
              
                          var id = 1;
                          var lastItem = DataSource.CommentsList.LastOrDefault();
                          if (lastItem != null)
                          {
                              id = lastItem.Id + 1;
                          }
                          comment.Id = id;
                          DataSource.CommentsList.Add(comment);
              
                          // ارسال آی دی با فرمت خاص مهم است
                          return Request.CreateResponse(HttpStatusCode.Created, new { comment = comment });
                      }
                  }
              }
              در اینجا توسط requestMessage به محتوای ارسال شده‌ی به سرور که همان شیء JSON ارسالی است، دسترسی خواهیم داشت. سپس متد JObject.Parse، آن‌را به صورت عمومی تبدیل به یک شیء JSON می‌کند و نهایتا با استفاده از متد SelectToken آن می‌توان ریشه‌ی comment و یا در کنترلر مطالب، ریشه‌ی post را انتخاب و سپس تبدیل به شیء Comment و یا Post کرد.
              همچنین فرمت return نهایی هم مهم است. در این حالت خروجی ارسالی به سمت کاربر، باید مجددا با فرمت JSON API باشد؛ یعنی باید comment اصلاح شده را به همراه ریشه‌ی comment ارسال کرد. در اینجا نیز anonymous object تهیه شده، چنین کاری را انجام می‌دهد.


              Lazy loading در Ember data

              تا اینجا اگر برنامه را اجرا کنید، لیست مطالب صفحه‌ی اول را مشاهده خواهید کرد، اما لیست نظرات آن‌ها را خیر؛ از این جهت که ضرورتی نداشت تا در بار اول ارسال لیست مطالب به سمت کاربر، تمام نظرات متناظر با آن‌ها را هم ارسال کرد. بهتر است زمانیکه کاربر یک مطلب خاص را مشاهده می‌کند، نظرات خاص آن‌را به سمت کاربر ارسال کنیم.
              در تعاریف سمت کاربر Ember data، پارامتر دوم رابطه‌ی hasMany که با async:true مشخص شده‌است، دقیقا معنای lazy loading را دارد.
              Blogger.Post = DS.Model.extend({
                 title: DS.attr(),
                 body: DS.attr(),
                 comments: DS.hasMany('comment', { async: true } /* lazy loading */)
              });
              در سمت سرور، دو راه برای فعال سازی این lazy loading تعریف شده در سمت کاربر وجود دارد:
              الف) Idهای نظرات هر مطلب را به صورت یک آرایه، در بار اول ارسال لیست نظرات به سمت کاربر، تهیه و ارسال کنیم:
              namespace EmberJS03.Models
              {
                  public class Post
                  {
                      public int Id { set; get; }
                      public string Title { set; get; }
                      public string Body { set; get; }
               
                      // lazy loading via an array of IDs
                      public int[] Comments { set; get; } 
                  }
              }
              در اینجا خاصیت Comments، تنها کافی است لیستی از Idهای نظرات مرتبط با مطلب جاری باشد. در این حالت در سمت کاربر اگر مطلب خاصی جهت مشاهده‌ی جزئیات آن انتخاب شود، به ازای هر Id ذکر شده، یکبار دستور Get صادر خواهد شد.
              ب) این روش به علت تعداد رفت و برگشت بیش از حد به سرور، کارآیی آنچنانی ندارد. بهتر است جهت مشاهده‌ی جزئیات یک مطلب، تنها یکبار درخواست Get کلیه نظرات آن صادر شود.
              برای اینکار باید مدل برنامه را به شکل زیر تغییر دهیم:
              namespace EmberJS03.Models
              {
                  public class Post
                  {
                      public int Id { set; get; }
                      public string Title { set; get; }
                      public string Body { set; get; }
               
                      // load related models via URLs instead of an array of IDs
                      // ref. https://github.com/emberjs/data/pull/1371
                      public object Links { set; get; }
               
                      public Post()
                      {
                          Links = new { comments = "comments" }; // api/posts/id/comments
                      }
                  }
              }
              در اینجا یک خاصیت جدید به نام Links ارائه شده‌است. نام Links در Ember data استاندارد است و از آن برای دریافت کلیه اطلاعات لینک شده‌ی به یک مطلب استفاده می‌شود. با تعریف این خاصیت به نحوی که ملاحظه می‌کنید، اینبار Ember data تنها یکبار درخواست ویژه‌ای را با فرمت api/posts/id/comments، به سمت سرور ارسال می‌کند. برای مدیریت آن، قالب مسیریابی پیش فرض {api/{controller}/{id را می‌توان به صورت {api/{controller}/{id}/{name اصلاح کرد:
              namespace EmberJS03
              {
                  public class Global : System.Web.HttpApplication
                  {
               
                      protected void Application_Start(object sender, EventArgs e)
                      {
                          RouteTable.Routes.MapHttpRoute(
                             name: "DefaultApi",
                             routeTemplate: "api/{controller}/{id}/{name}",
                             defaults: new { id = RouteParameter.Optional, name = RouteParameter.Optional }
                             );
               
                          var settings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
                          settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                      }
                  }
              }
              اکنون دیگر درخواست جدید api/posts/3/comments با پیام 404 یا یافت نشد مواجه نمی‌شود.
              در این حالت در طی یک درخواست می‌توان کلیه نظرات را به سمت کاربر ارسال کرد. در اینجا نیز ذکر ریشه‌ی comments همانند ریشه posts، الزامی است:
              namespace EmberJS03.Controllers
              {
                  public class PostsController : ApiController
                  {
                      //GET api/posts/id
                      public object Get(int id)
                      {
                          return
                              new
                              {
                                  posts = DataSource.PostsList.FirstOrDefault(post => post.Id == id),
                                  comments = DataSource.CommentsList.Where(comment => comment.Post == id).ToList()
                              };
                      }
                  }
              }


              پردازش‌های async و متد transitionToRoute در Ember.js

              اگر متد حذف مطالب را نیز به کنترلر Posts اضافه کنیم:
              namespace EmberJS03.Controllers
              {
                  public class PostsController : ApiController
                  {
                      public HttpResponseMessage Delete(int id)
                      {
                          var item = DataSource.PostsList.FirstOrDefault(x => x.Id == id);
                          if (item == null)
                              return Request.CreateResponse(HttpStatusCode.NotFound);
              
                          DataSource.PostsList.Remove(item);
              
                          //حذف کامنت‌های مرتبط
                          var relatedComments = DataSource.CommentsList.Where(comment => comment.Post == id).ToList();
                          relatedComments.ForEach(comment => DataSource.CommentsList.Remove(comment));
              
                          return Request.CreateResponse(HttpStatusCode.OK, new { post = item });
                      }
                  }
              }
              قسمت سمت سرور کار تکمیل شده‌است. اما در سمت کاربر، چنین خطایی را دریافت خواهیم کرد:
               Attempted to handle event `pushedData` on  while in state root.deleted.inFlight.
              منظور از حالت inFlight در اینجا این است که هنوز کار حذف سمت سرور تمام نشده‌است که متد transitionToRoute را صادر کرده‌اید. برای اصلاح آن، فایل Scripts\Controllers\post.js را باز کرده و پس از متد destroyRecord، متد then را قرار دهید:
              Blogger.PostController = Ember.ObjectController.extend({
                  isEditing: false,
                  actions: {
                      edit: function () {
                          this.set('isEditing', true);
                      },
                      save: function () {
                          var post = this.get('model');
                          post.save();
               
                          this.set('isEditing', false);
                      },
                      delete: function () {
                          if (confirm('Do you want to delete this post?')) {
                              var thisController = this;
                              var post = this.get('model');
                              post.destroyRecord().then(function () {
                                  thisController.transitionToRoute('posts');
                              });
                          }
                      }
                  }
              });
              به این ترتیب پس از پایان عملیات حذف سمت سرور، قسمت then اجرا خواهد شد. همچنین باید دقت داشت که this اشاره کننده به کنترلر جاری را باید پیش از فراخوانی then ذخیره و استفاده کرد.


              کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:
              EmberJS03_05.zip
              مطالب
              الگوریتم‌های داده کاوی در SQL Server Data Tools یا SSDT - قسمت چهارم - الگوریتم‌ Clustering یا خوشه بندی
              در قسمت قبل با الگوریتم های Decision trees و Linear Regression آشنا شدیم. در این قسمت به الگوریتم Clustering یا خوشه بندی می‌پردازیم.

              مقدمه


              تصور کنید شما بچه‌ای هستید که با یک کیسه تیله روی زمین نشسته‌اید. لحظه‌ای که تیله‌ها را از کیسه روی زمین می‌ریزید، متوجه می‌شوید که تیله‌ها، چهار رنگ دارند (آبی، قرمز، سبز و زرد). تیله‌ها را در چهار گروه با توجه به رنگ‌هایشان قرار می‌دهید. اما بعد متوجه می‌شوید که اندازه بعضی از تیله‌ها متوسط و برخی بزرگ و تعدادی هم کوچک هستند. شما تصمیم می‌گیرید که تیله‌های کوچک و متوسط، در کنار یکدیگر و در یک گروه قرار گیرند؛ اما تیله‌های بزرگ را در یک گروه دیگر قرار می‌دهید. چرا که تنها یکی از آن‌ها را باید به هر بازیکن داد. تبریک می‌گویم! شما یک عمل خوشه بندی را انجام دادید.
              حال زمانیکه قدری با دقت بیشتری به خوشه بندی خود نگاه می‌کنید، متوجه می‌شوید که برخی از تیله‌ها کریستالی، برخی دیگر سه پر و چهارپر، بعضی از آن‌ها صاف و صیقلی و بعضی دیگر دارای خراش می‌باشند. اینجاست که قدری سردرگم می‌شوید. آیا باید همان گروه بندی ساده براساس رنگ و اندازه را مدنظر قرار دهید، یا بهتر است عوامل دیگری مانند سبک، مواد تشکیل دهنده و وضعیت ظاهری را نیز اضافه کنید؟
              خوشه بندی، یک عمل انسانی راحت، طبیعی و حتی می‌شود گفت اتوماتیک برای مواجه شدن با مجموعه ویژگی‌های کوچک می‌باشد. اما همینطور که ویژگی‌ها بیشتر می‌شوند، حل مساله برای انسان خیلی سخت و غیرممکن می‌شود. ذهن یک انسان معمولی، تقریبا قادر به درنظر گرفتن 5 یا 6 بُعد می‌باشد. این درحالی است که مجموعه داده‌های مدرن گاها دارای ده‌ها بعد (اگر نگوییم صدها) می‌باشند.
              الگوریتم خوشه بندی مایکروسافت، گروه بندی‌هایی ذاتی را داخل مجموعه داده شما پیدا می‌کند که ممکن است به چشم نیایند. به عبارت دیگر، متغیرهای پنهانی را که به طور دقیق داده‌های شما را خوشه بندی می‌کنند، پیدا می‌نماید. برای مثال فرض کنید که شما جزیی از یک گروه بزرگ مسافران هستید که در بخش نوار نقاله حمل بار در فرودگاه منتظر برداشتن چمدان می‌باشید. متوجه می‌شوید که درصد قابل توجهی از مسافران شلوار کوتاه پوشیده و پوستشان در اثر آفتاب قدری تیره‌تر شده است؛ درحالیکه مابقی مسافران لباس گرم مانند ژاکت و کت به تن دارند. بنابراین به یک حقیقت پی می‌برید. یک گروه از نواحی گرمسیری آمده‌اند و دیگری از یک جای سرد و مرطوب. این همان متغیر پنهان است.

              الگوریتم Clustering یا خوشه بندی مایکروسافت  

              الگوریتم خوشه بندی مایکروسافت رفتارهای خاصی را در مواجه با نوع ویژگی‌ها از خود نشان می‌دهد. در ارتباط با ستون‌های ورودی (Input) و ورودی-خروجی (Predict) مانند آنچه قبلا گذشت عمل می‌کند. البته با یک تفاوت و آن اینکه ستون‌های ورودی-خروجی در حین پیش بینی قابل انتخاب هستند؛ حال آنکه ستون‌های ورودی اینطور نیستند. ستون‌هایی که فقط خروجی (Predict Only) هستند، در طی فاز خوشه بندی برای آموزش مدل به کار نمی‌روند.
              همانطور که قبلا نیز اشاره شد، خوشه بندی، رایج‌ترین عملی است که با این الگوریتم انجام می‌دهند. بنابراین جهت کشف خوشه بندی‌ها در یک مجموعه داده می‌توان این الگوریتم را روی مجموعه داده اعمال کرده و خوشه بندی‌های کشف شده را برچسب زد. بعد از برچسب زدن می‌توان از آن، جهت گزارش گیری و تحلیل داده‌ها استفاده نمود. از آنجا که این الگوریتم سربار پردازشی و حافظه‌ای زیادی دارد، بنابراین در رابطه با مجموعه داده‌های بزرگ (رکوردهای میلیونی و پیچیده) بهتر است که فقط بخش کوچکی از داده را برای آموزش استفاده کرده (که البته کافی و وافی است) و از طریق آن‌ها ویژگی‌های خوشه بندی را کشف کرد.
              توسط این الگوریتم می‌توان مدل را تجزیه-تحلیل نمود و نابهنجاری‌ها را نیز تشخیص داد.

              محتوای مدل خوشه بندی

              درک محتوای مدل خوشه بندی بسیار ساده است. شکل زیر دیاگرام خوشه بندی یا Cluster Diagram می‌باشد. همانطور که در شکل آمده است SSAS در نشان دادن نام هر گره به خوبی عمل نمی‌کند زیرا هر گره توسط Cluster و یک ایندکس نشان داده می‌شود و نام معناداری برای آن در نظر نمی‌گیرد. برای مثال خوشه مربوط به تیله‌های آبی بزرگ سه پر (برای مثال Cluster2، Cluster1 و ....).


              بنابراین برای برچسب زدن مناسب برروی هر گره باید به شکل زیر عمل کرد:
              • مرور اجمالی مدل: توسط دو برگه اول یعنی Cluster Diagram و Cluster Profiles می‌توان توپولوژی مدل خوشه بندی را به دست آورد. در برگه Cluster Diagram هر خوشه یک گره را تشکیل می‌دهد که براساس شباهت به یکدیگر متصل شده‌اند. بدیهی است خوشه‌هایی که در ضعیف‌ترین ارتباط هم به یکدیگر متصل نیستند، هیچگونه شباهتی ندارند. براساس میزان شباهت، نوار اتصال بین گره‌ها، تیره‌تر یا روشن‌تر می‌گردد. همانطور که در شکل فوق مشخص است هرچه این نوار تیره‌تر باشد، بیانگر شباهت بیشتر بین دو خوشه است. Cluster Profiles یک ستون را برای هر خوشه و یک سطر را برای هر ویژگی درنظر می‌گیرد. درصورتیکه یک ویژگی برای شما جالب توجه باشد می‌توانید به صورت افقی توزیع آن را در خوشه‌های مختلف مشاهده کنید. هر زمانیکه آیتمی نظر شما را جلب کرد می‌توان به سلول‌های مجاور یا سلول‌های هم خوشه آن نگاه کرد و مفهوم آن خوشه را بیشتر درک نمود. با کلیک برروی هر یک از سلول‌ها می‌توان جزییات مربوط به آن سلول را مشاهده کرد. برای مثال می‌توان فهمید این خوشه براساس چه شروطی ایجاد شده‌است. شکل زیر نمایی از Cluster Profiles را نشان می‌دهد. همانطور که در قسمت قبل نیز بحث شد، نوارهای هیستوگرام مربوط به ویژگی‌های گسسته بوده و نوارهای الماسی نشان دهنده ویژگی‌های پیوسته می‌باشند.


              • انتخاب یک خوشه و تشخیص وجه تمایز آن: از برگه Cluster Diagram شروع می‌نماییم. یک راه این است که ببینیم کدام خوشه‌ها، قوی‌ترین ارتباط را دارند و یکی از آن‌ها را انتخاب نماییم. راه دیگر این است که خوشه‌ای را انتخاب کنیم که به نظر دور  از بقیه خوشه‌ها است. پس از انتخاب خوشه موردنظر به تب Cluster Characteristics می‌رویم. همانطور که در شکل زیر مشخص است این بخش مشخصات حالات مختلف یک خوشه را توسط نمودار احتمال با روند کاهشی  نشان می‌دهد. بنابراین می‌توان متوجه شد چه ویژگی هایی و با چه احتمالی سبب ایجاد یک خوشه شده‌اند.

                ممکن است تعدادی ویژگی با احتمال بالا در یک خوشه وجود داشته باشند اما سوال اینجاست که از کجا معلوم که تمام این ویژگی‌ها در خوشه‌های دیگر نیز این احتمال را نداشته باشند؟ برای اینکه متوجه شویم که بیشتر چه ویژگی سبب وجه تمایز این خوشه شده‌است باید به برگه Cluster Discrimination مراجعه کنیم که نمونه‌ای از آن در شکل زیر آمده است.

                 در این بخش می‌توان خصوصیات خوشه مدنظر را با خوشه‌های دیگر یا با متمم خوشه (Complement) مقایسه کرد و توسط آن، ویژگی‌هایی را که سبب وجه تمایز این خوشه شده‌اند، مشاهد نمود. توجه به این نکته ضروری است که نوار نشان داده شده در رابطه با هر ویژگی تنها نشان دهنده میزان توجه به آن ویژگی در آن خوشه است و به این معنی نیست که خوشه‌های دیگر عاری از آن ویژگی هستند.

              • تشخیص چگونگی تمایز یک خوشه از خوشه‌های نزدیک به آن: حال می‌توان با اطلاعاتی که تا به حال کسب کرده‌ایم یک خوشه را به صورت دقیق برچسب بزنیم. اما ممکن است این خوشه خیلی شبیه به خوشه‌های دیگر باشد و بنابراین مجبور شویم که یک برچسب را بر روی دو خوشه بزنیم. پس توصیه می‌شود که خوشه انتخاب شده را با خوشه‌های همسایه مقایسه کنیم. برای این منظور به تب Cluster Diagram مراجعه نموده و نگاه می‌کنیم که کدام خوشه‌ها به خوشه مدنظر ما نزدیک هستند. اگر هیچ اتصال قوی بین دو خوشه نبود کار تمام است. اما اگر اینگونه نبود آنگاه باید مجددا به تب Cluster Characteristics مراجعه نموده و تک تک ویژگی‌های دو خوشه نزدیک به هم را مقایسه نماییم، تا فرق بین آن‌ها را در صورت وجود به دست آوریم.

              خوشه بندی سخت و خوشه بندی نرم

              مهمترین فرق بین الگوریتم‌های خوشه بندی، روشی است که الگوریتم‌ها در رابطه با انتساب حالت‌ها، به خوشه‌ها اتخاذ می‌کنند. الگوریتم خوشه بندی مایکروسافت، دو روش مختلف را برای اینکار دارند: K-means و Expectation Maximization. روش اول (شکل سمت چپ) براساس فاصله حالت‌ها نسبت به خوشه‌ها، آن‌ها را نسبت می‌دهد و در پایان مرکز خوشه طوری قرار خواهد گرفت که وسط حالت‌ها باشد. به این تکنیک، خوشه بندی سخت می‌گویند (شکل سمت چپ) زیرا همانطور که در شکل سمت چپ مشخص است هر شیء فقط و فقط در یک خوشه قرار می‌گیرد و هیچ یک از خوشه‌ها با یکدیگر هم پوشانی ندارند. روش دوم (شکل سمت راست) به جای استفاده محض از مقیاس فاصله، از یک مقیاس احتمالی استفاده می‌کند. این روش یک منحنی زنگوله شکل را که دارای میانگین و انحراف معیار است برای هر بُعد درنظر می‌گیرد. چنانچه نقطه‌ای داخل یک منحنی بیفتد با یک احتمال معینی به آن خوشه نسبت داده می‌شود. به دلیل اینکه منحنی‌ها می‌توانند هم پوشانی داشته باشند، بنابراین هر نقطه می‌تواند به چندین خوشه منتسب شود؛ البته با احتمالات مختلف. به این تکنیک، خوشه بندی نرم گفته می‌شود (شکل سمت راست). این تکنیک در شناسایی خوشه‌های پیوسته خیلی موثر است مانند وضعیت تراکم جمعیت مناطق. 


              خوشه بندی با قابلیت مدرج کردن

              یکی از مسایلی که در الگوریتم خوشه بندی وجود دارد این است که جهت به دست آوردن خوشه بندی مناسب، نیاز به تکرار آموزش برروی داده‌ها است. این تکرار در مجموعه داده‌های کوچک، مشکلی ایجاد نمی‌کند، اما در رابطه با مجموعه داده‌های بزرگ این امر امکان پذیر نیست. زیرا کل مجموعه داده داخل رم قرار می‌گیرد و مشکلات کارآیی را ایجاد می‌کند. الگوریتم خوشه بندی مایکروسافت یک چارچوب برای مدرج کردن خوشه بندی را در اختیار ما قرار می‌دهد که با استفاده از آن می‌توان بر این مشکل فایق آمد. این مهم توسط پارامتر Sample_Size مرتفع می‌شود که یکی از پارامترهای این الگوریتم می‌باشد. همانطور که در قسمت قبل نیز گفته شد دسترسی به پارامترهای هر الگوریتم به شکل زیر صورت می‌پذیرد:
              مراجعه به برگه mining models ، کلیک بر روی الگوریتم، رفتن به پنجره properties  الگوریتم. حال می‌توان  به بخش Algorithm Parameters رفت و پارامترها را مقداردهی کرد. البته اگر از نظر حافظه رم مشکلی ندارید، می‌توانید مقدار این پارامتر را صفر درنظر بگیرید و با این کار تمام حافظه رم را به پردازش الگوریتم اختصاص بدهید، تا الگوریتم به هر میزانی که نیاز دارد، از حافظه رم استفاده نماید.
              مطالب
              C# 7.1 - default Literals
              Literal چیزی است مانند null و در حقیقت یک واژه‌ی کلیدی‌است که دارای مقداری مشخص می‌باشد. واژه کلیدی default نیز مفهوم مشابهی را به همراه دارد. تا پیش از C# 7.1 برای دسترسی به مقدار پیش‌فرض value types به صورت ذیل عمل می‌شد:
               int a = default(int);
              در اینجا مقدار پیش‌فرض نوعی که بین پرانتزها ذکر می‌شود، بازگشت داده خواهد شد. اگر int ذکر شود، صفر و اگر bool ذکر شود، مقدار false را بازگشت می‌دهد. همچنین در اینجا اگر یک reference type مانند string ذکر شود، مقدار null بازگشت داده خواهد شد.
              var number = default(int); // 0
              var date = default(DateTime); // DateTime.MinValue
              var obj = default(object); // null
              در C# 7.1 با بهبود کامپایلر، مفهوم type inference پیاده سازی شده‌است. به این معنا که در مثال فوق مشخص است که a نوع int دارد. بنابراین نیازی نیست تا default به همراه ذکر صریح int باشد و می‌توان int را از آن حذف کرد:
              int a = default; // 0
              Guid guid = default; // 00000000-0000-0000-0000-000000000000


              مثال‌هایی از default Literals در C# 7.1

               C# 7.1
               C# 7.0
               
               int i = default;
               int i = default(int);
               Local Variable Defaults  
               Person Create() => default;
               Person Create() => default(Person);
               Local function 
               Person Create(string name, int age = default)
               Person Create(string name, int age = default(int))
               Optional Parameter Default Value 
               (string Name, int Age) person = ("User 1", default);
               (string Name, int Age) person = ("User 1", default(int));
               Tuple Element Default Value 
              Person p = new Person
              {
                Name = default,
                Age = default
              };
              Person p = new Person
              {
                Name = default(string),
                Age = default(int)
              };
               Object Initializer Default Value 
              var people = new[]
              {
                new Person(),
                default,
                new Person()
              };
              
              var ages = new[] {18, default, 50};
              var people = new[]
              {
                new Person(),
                default(Person),
                new Person()
              };
              
              var ages = new[] {18, default(int), 50};
               Array Initializer Default Value 
               int i = default;
              Console.WriteLine(i is default);
               int i = default(int);
              Console.WriteLine(i is default(int)); // true
               Is Operator 
               // Local method returning a tuple
              (T, T) CreateTwo<T>() => (default, default);
               // Local method returning a tuple
              (T, T) CreateTwo<T>() => (default(T), default(T));
               Generic Defaults 
               bool IsAnswerKnown()=> false;
              int? p = IsAnswerKnown() ? 42 : default;
               bool IsAnswerKnown()=> false;
              int? p = IsAnswerKnown() ? 42 : (int?)null;
               Conditional Operator Defaults 

              در این مثال‌ها مفهوم type inference را بهتر می‌توان مشاهده کرد. برای مثال در آرایه‌ی ذیل چون اعضای آن int هست، مقدار default نیز به همان مقدار پیش‌فرض int اشاره می‌کند و همچنین نوع آرایه نیز int درنظر گرفته می‌شود و نیازی به ذکر آن نیست:
               var ages = new[] {18, default, 50};
              اما اگر در اینجا اعداد را حذف کنیم و default باقی بماند:
               var ages = new[] { default };
              دیگر تشخیص نوع پیش‌فرض میسر نبوده و این قطعه از کد کامپایل نخواهد شد.
              نمونه‌ی دیگر آن قطعه کد ذیل است:
              string s = default;
              if(s == default)
              {
              
              }
              در اینجا s از نوع string است و مقایسه‌ی انجام شدهی در قطعه کد if، بر اساس مقدار پیش فرض string یا همان null صورت خواهد گرفت.
              و یا در مقایسه‌ی ذیل 1.5 یک عدد double است. بنابراین default در اینجا به مقدار پیش‌فرض double و یا 0.0 اشاره می‌کند:
              int a = default;
              var x = a > 0 ? default : 1.5;