مطالب
JQuery Plugins #2
در قسمت اول آموزش 1# jQuery Plugin با نحوه ساخت اولیه پلاگین در جی کوئری آشنا شدید. در ادامه به موارد دیگری خواهم پرداخت.

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

توابع پلاگین
تحت هیچ شرایطی نباید یک پلاگین، در چندین فضای نام، به شی Jquery.fn اضافه گردند. به مثال زیر توجه نمایید:
(function( $ ){

  $.fn.tooltip = function( options ) { 
    // این
  };
  $.fn.tooltipShow = function( ) {
    // تعریف
  };
  $.fn.tooltipHide = function( ) { 
    // بد است
  };
  $.fn.tooltipUpdate = function( content ) { 
    // !  
  };

})( jQuery );
همین طور که در مثال بالا مشاهده می‌کنید، پلاگین به شکل بدی تعریف شده و هر تابع در یک فضای نام جداگانه تعریف گردیده‌است. برای این کار شما باید تمام توابع را در یک  متغیر تعریف و آن را به پلاگین خود پاس دهید و توابع را با نام رشته ای صدا بزنید.
(function( $ ){

  var methods = {
    init : function( options ) { 
      // این 
    },
    show : function( ) {
      // تعریف
    },
    hide : function( ) { 
      // خوب است
    },
    update : function( content ) { 
      // ! 
    }
  };

  $.fn.tooltip = function( method ) {
    
    // منطق تابع را  از اینجا صدا زده ایم
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    
  
  };

})( jQuery );
توضیح: متغیر method اگر در متغیر methods توابع موجود باشد، تابع هم نام آن و در صورت داشتن پارامتر ورودی، به آن تابع پاس داده شده و برگردانده می‌شود (در واقع صدا زده می‌شود). در غیر اینصورت اگر نوع مقدار ورودی، object بود تابع init آن صدا زده می‌شود وگرنه پیام خطا ارسال می‌گردد.
برای استفاده از پلاگین بصورت زیر عمل می‌کنیم:
// تابع init صدا زده می‌شود
$('div').tooltip();
و
// تابع update با پارامتر صدا زده می‌شود
$('div').tooltip('update', 'This is the new tooltip content!');
این معماری به شما امکان کپسوله کردن توابع در پلاگین را می‌دهد.

رویداد ها
 یکی از روش‌های کمتر شناخته شده انقیاد توابع در فضای نام، امکان انقیاد رویداد‌ها است. اگر پلاگین شما یک رویداد را انقیاد نماید، این یک عمل و تمرین خوب استفاده از فضای نام می‌باشد. بدین ترتیب اگر لازم باشد که انقیاد یک رویدا را حذف نمایید، بدون تداخل با دیگر رویداد‌ها و بدون اینکه در یک شی دیگر از این پلاگین، اختلالی ایجاد نماید می‌توان آن را حذف نمود. به مثال زیر توجه نمایید.
(function( $ ){

  var methods = {
     init : function( options ) {

       return this.each(function(){
         $(window).bind('resize.tooltip', methods.reposition);
       });

     },
     destroy : function( ) {

       return this.each(function(){
         $(window).unbind('.tooltip');
       })

     },
     reposition : function( ) { 
       // ... 
     },
     show : function( ) { 
       // ... 
     },
     hide : function( ) {
       // ... 
     },
     update : function( content ) { 
       // ...
     }
  };

  $.fn.tooltip = function( method ) {
    
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    
  
  };

})( jQuery );
این همان مثال قبل است که وقتی پلاگین با تابع Init مقدار دهی اولیه می‌شود، تابع reposition به رویداد resize پنجره در فضای نام پلاگین tooltip انقیاد می‌شود. پس از آن اگر توسعه دهنده نیاز داشت تا tooltip را از بین ببرد، با صدا زدن تابع destroy می تواند بصورت امن انقیاد ایجاد شده را حذف نماید.
$('#fun').tooltip();
// مدتی بعد...
$('#fun').tooltip('destroy');

ادامه دارد...
مطالب دوره‌ها
شناسه ها و استفاده از Let
#F هم مانند سایر زبان‌های برنامه نویسی از یک سری Data Type به همراه عملگر و Converter پشتیبانی می‌کند که در ابتدا لازم است یک نگاه کلی به این موارد بیندازیم. به دلیل آشنایی اکثر دوستان به این موارد و به دلیل اینکه تکرار مکررات نشود از توضیح در این موارد خودداری خواهم کرد.(در صورت مبهم بودن می‌توانید از قسمت پرسش و پاسخ استفاد نمایید)
Basic Literal


جدول بالا کاملا واضح است و برنامه نویسان دات نت نظیر #C با انواع داده ای بالا آشنایی دارند. فقط در مورد گزینه آخر unit در فصل‌های بعدی توضیح خواهم داد.

Arithmetic Operators
(عملگر‌های محاسباتی)

Simple String (کار با نوع داده رشته ای)


بعد از بررسی موارد بالا حالا به معرفی شناسه‌ها می‌پردازم. شناسه‌ها در #F راهی هستند برای اینکه شما به مقادیر نام اختصاص دهید. برای اختصاص نام به مقادیر کافیست از کلمه کلیدی let به همراه یک نام  و علامت = و یک عبارت استفاده کنید. چیزی شبیه به تعریف متغیر در سایر زبان‌ها نظیر #C. دلیل اینکه در #F به جای واژه متغیر از شناسه استفاده می‌شود این است که شما می‌توانید به یک شناسه تابعی را نیز اختصاص دهید و مقدار شناسه‌ها دیگر قابل تغییر نیست. در #F کلمه متغیر یک واژه نادرست است چون زمانی که شما یه یک متغیر مقدار اختصاص می‌دهید، مقدار  اون متغیر دیگه قایل تغییر نیست. برای همین اکثر برنامه نویسان #F به جای استفاده از واژه متغیر از واژه مقدار یا شناسه استفاه می‌کنند. برای همین از واژه متغیر برای نام گذاری استفاده نمی‌شود. (البته در #F در بعضی مواقع ما شناسه‌ها رو دوباره تعریف می‌کنیم که چیزی شبیه به استفاده از متغیر هاست ولی با اندکی تفاوت. در این فصل تمرکز ما بر روی شناسه هایی است که مقدارشان تغییر نمی‌کند ولی در فصل برنامه نویسی دستوری به تفصیل در این باره توضیح داده شده است)
let x = 42
در بالا یک شناسه به نام x تعریف شد که مقدار 42 را دریافت کرد. در #F یک شناسه می‌تواند دارای یک مقدار معین باشد یا به یک تابع اشاره کند. این بدین معنی است #F معنی حقیقی برای تابع و پارامتر‌های آن ندارد و همه چیز رو به عنوان مقدار در نظر می‌گیرد.
let myAdd = fun x y -> x + y
کد بالا تعریف یک شناسه به نام myAdd است که به تابعی اشاره می‌کنه که دو پارامتر ورودی دارد و در بدنه آن مقدار پارامتر‌ها با هم جمع می‌شوند.(تعریف توابع به صورت مفصل بحث خواهد شد.) نکته جالب این است که تابع تعریف شده نام ندارد و #F دقیقا با توابع همون رفتاری رو داره که با شناسه‌ها دارد.
let raisePowerTwo x = x ** 2.0
در کد بالا شناسه ای تعریف شده است با نام raisePowerTwo که یک پارامتر ورودی داره به نام x و در بدنه آن (هرچیزی که بعد از = قرار گیرد) مقدار x رو به توان دو می‌کنه.

نام گذاری شناسه ها

برای نام گذاری شناسه‌ها نام انتخابی یا باید با Underscore شروع شود یا با حروف. بعد از آن می‌تونید از اعداد هم استفاده کنید.(نظیر سایر زبان‌های برنامه نویسی)
#F از unicode هم پشتیبانی می‌کنه یعنی می‌تونید متغیری به صورت زیر رو تعریف کنید.
let مسعود = ""
اگر احساس می‌کنید که قوانین نام گذاری در #F کمی محدود کننده است می‌تونید از علامت '' ''  استفاده کنید و در بین این علامت  هر کاراکتری که می‌خواهید رو قرار دهید و #F اونو به عنوان نام شناسه قبول خواهد کرد. برای نمونه
let ``more? `` = true
یا
let ``class`` = "style"
حتی امکان استفاده از کلمات کلیدی هم نظیر class به این روش وجود دارد.

محدوده تعریف شناسه ها
به دلیل اینکه در #F از {} به عنوان شروع و اتمام محدوده استفاده نمی‌شود دونستن و شناختن محدوده توابع بسیار مهم و ضروری است. چون اگر از شناسه ای که در یک محدوده در دسترس نباشد استفاده کنید با خطای کامپایلر متوقف خواهید شد.
همون بحث متغیر‌های محلی و سراسری (در سایر زبان ها) در این جا نیز صادق است یعنی در #F شناسه‌های سراسری و محلی خواهیم داشت. تمام شناسه ها، چه اون هایی که در توابع استفاده می‌شوند و چه اونهایی که به مقادیر اشاره می‌کنند محدودشون از نقطه ای که تعریف می‌شوند تا جایی که اتمام استفاده از اونهاست تعریف شده است. برای مثال اگر یک شناسه رو در بالای فایل تعریف کنید که یک مقدار دارد تا پایان SourceFile قابل استفاده است.( به دلیل نبود مفهوم کلاس از واژه sourceFile استفاده کردم). هم چنین شناسه هایی که در توابع تعریف می‌شوند فقط در همون توابع قابل استفاده هستند.
حالا سوال این است که با نبودن {} چگونه محدوده خود توابع مشخص میشود؟
در #F با استفاده از فضای خای یا space محدوده شناسه‌ها و توابع رو مشخص می‌کنیم.  برای روشن شدن مطلب به مثال زیر دقت کنید.
let test a b =
    let dif = b - a
    let mid = dif / 2
    mid + a

printfn "(test 5 11) = %i" (test 5 11)
printfn "(test 11 5) = %i" (test 11 5)
ابتدا اختلاف بین دو ورودی محاسبه می‌شود و در یک شناسه به نام dif قرار می‌گیرد. برای اینکه مشخص شود که این شناسه خود عضو یک تابع دیگر به نام test است از 4 فضای خالی استفاده شده است. در خط بعدی شناسه mid مقدار شناسه dif رو بر 2 تقسیم می‌کند. در انتها نیز مقدار mid با مقدار a جمع می‌شود و حاصل برگشت داده می‌شود.(انتهای بدنه تابع)
نکته مهم: به جای استفاده از فضای خالی(space) نمی‌تونید از TAB استفاده کنید.

LIGHTWEIGHT SYNTAX یا VERBOSE SYNTAX


در #F دو نوع سبک کد نویسی وجود دارد. یکی lightweight و دیگری Verbose. البته اکثر برنامه نویسان از سبک lightweight که به صورت پیش فرض در #F تعبیه شده است استفاده می‌کنند ولی آشنایی با سبک verbose نیز به عنوان برنامه نویس #F ضروری است. ما نیز به تبعیت از سایرین از سبک lightweight استفاده خواهیم کرد ولی یک فصل به عنوان مطالب تکمیلی اختصاص دادم که تفاوت این دو سبک را در طی چندین مثال بیان میکند.
همان طور که قبلا بیان شد #F بر اساس زبان OCaml پیاده سازی شده است. زبان OCaml مانند #F، یک زبان LIGHTWEIGHT SYNTAX نیست. LIGHTWEIGHT SYNTAX  بدین معنی است محدوده شناسه‌ها بر اساس فضای خالی بین اون‌ها مشخص می‌شود نه با ;. (البته استفاده از ; به صورت اختیاری است)
بازنویسی مثال بالا
let halfWay a b =
let dif = b - a in
let mid = dif / 2 in
mid + a
برای اینکه کامپایلر #F متوجه شود که قصد کدنویسی به سبک lightweight رو نداریم، باید در ابتدای هر فایل از دستور زیر استفاده کنیم.
#light "off"
مطالب
کارهایی جهت بالابردن کارآیی Entity Framework #1
امروزه اهمیت استفاده از  Entity Framework بر هیچ کسی پوشیده نیست؛ اما در صورتی که به مفاهیم ابتدایی آن آشنایی نداشته باشید ممکن است در دام هایی بیفتید که استفاده از آن کم رنگ شود. در زیر به توصیه‌هایی جهت بالابردن کارآیی برنامه‌های مبتنی بر EF اشاره خواهیم کرد.
  • تنها دریافت رکوردهای مورد نیاز

EF راهی برای کار با اشیاء POCO، بدون آگاهی از مقادیرشان می‌باشد. اما هنگام فرآیند دریافت و یا به روزرسانی مقادیر این اشیاء از بانک اطلاعاتی، رفت و برگشت هایی انجام می‌شود که اطلاع از آنها بسیار حیاتی و ضروری است. به این فرآیند materiallization می‌گویند.
string city = "New York";
List<School> schools = db.Schools.ToList();
List<School> newYorkSchools = schools.Where(s => s.City == city).ToList();

در کد بالا ابتدا کلیه ردیف‌های جدول از دیتابیس به حافظه منتقل می‌شود و سپس برروی آنها کوئری مورد نظر اعمال می‌گردد که بشدت می‌تواند برای یک برنامه - خصوصا برنامه وب - به‌دلیل دریافت کلیه‌ی ردیف‌های جدول بسیار مخرب باشد. کوئری فوق را می‌توان به صورت زیر اصلاح کرد:

List<School> newYorkSchools = db.Schools.Where(s => s.City == city).ToList();
یا
IQueryable<School> schools = db.Schools;
List<School> newYorkSchools = schools.Where(s => s.City == city).ToList();
  • حداقل رفت و برگشت به دیتابیس

کد زیر را در نظر بگیرید:

string city = "New York";
List<School> schools = db.Schools.Where(s => s.City == city).ToList();
var sb = new StringBuilder();
foreach(var school in schools)
{
    sb.Append(school.Name);
    sb.Append(": ");
    sb.Append(school.Pupils.Count);
    sb.Append(Environment.NewLine);
}

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

توجه داشته باشید:

  • یک مدرسه می‌تواند چندین دانش آموز داشته باشد (وجود رابطه یک به چند)
  • LazyLoading فعال است
  • تعداد مدرسه‌های شهر نیویورک 200 عدد می‌باشد

اگر کوئری بالا را به‌وسیله‌ی یک پروفایلر بررسی نمایید، متوجه خواهید شد 1 + 200 رفت و برگشت به دیتابیس صورت گرفته است که به "N+1 select problem" معروف است. 1 مرتبه جهت دریافت لیست مدرسه‌های شهر نیویورک و 200 مرتبه جهت دریافت تعداد دانش آموزان هر مدرسه.

بدلیل فعال بودن Lazy Loading، زمانیکه موجودیتی فراخوانی می‌شود، سایر موجودیت‌های وابسته به آن، زمانی از دیتابیس فراخوانی خواهند شد که به آن‌ها دسترسی پیدا کنید. در حلقه‌ی foreach هم به ازای هر مدرسه (200 مدرسه) شهر نیویورک یک رفت و برگشت انجام می‌شود.

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

List<School> schools = db.Schools
    .Where(s => s.City == city)
    .Include(x => x.Pupils)
    .ToList();

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

  • تنها استفاده از ستون‌های مورد نیاز

فرض کنید قصد دارید نام و نام خانوادگی دانش آموزان یک مدرسه را بدست آورید.

int schoolId = 1;

List<Pupil> pupils = db.Pupils
    .Where(p => p.SchoolId == schoolId)
    .ToList();

foreach(var pupil in pupils)
{
    textBox_Output.Text += pupil.FirstName + " " + pupil.LastName;
    textBox_Output.Text += Environment.NewLine;
}
کد بالا تمام ستون‌های یک جدول را همراه با ستون‌های نام و نام خانوادگی جدول مربوطه را از دیتابیس فراخوانی می‌کند که باعث بروز 2 مشکل زیر می‌گردد:
  1. انتقال اطلاعات بلا استفاده که ممکن است باعث کاهش کارآیی Sql Server I/O و شبکه و اشغال حافظه‌ی کلاینت گردد.
  2. کاهش کارآیی ایندکس گذاری. فرض کنید برروی جدول دانش آموزان ایندکسی شامل 2 ستون نام و نام خانوادگی تعریف کرده‌اید. با انتخاب تمام ستونهای جدول توسط خط دوم (select * from...) به کارآیی ایندکس گذاری برروی این جدول آسیب زده‌اید. توضیح بیشتر در اینجا مطرح شده است.

اما راه حل:

var pupils = db.Pupils
    .Where(p => p.SchoolId == schoolId)
    .Select(x => new { x.FirstName, x.LastName })
    .ToList();
  • عدم تطابق نوع ستون با نوع خصیصه مدل

فرض کنید نوع ستون جدول دانش آموزان (VARCHAR(20 است و خصیصه کدپستی مدل دانش آموز مانند زیر تعریف شده است:

public string PostalZipCode { get; set; }

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

string zipCode = "90210";
var pupils = db.Pupils
    .Where(p => p.PostalZipCode == zipCode)
    .Select(x => new {x.FirstName, x.LastName})
    .ToList();
کوئری بالا منجر به تولید SQL زیر می‌گردد: (نوع پارامتر ارسالی NVARCHAR است در حالی که ستون از نوع VARCHAR)

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

همانطور که در شکل بالا مشخص است عملیات index scan از سایر عملیات‌ها پرهزینه‌تر است. حال به بررسی علت به‌وجود آمدن این عملیات پرهزینه خواهیم پرداخت.

Index Scan زمانی رخ می‌دهد که اس کیو ال سرور مجبور است هر صفحه‌ی از ایندکس را بخواند و شرایط را (کدپستی برابر 90210) اعمال نماید و نتیجه را برگرداند. Index Scan بسیار هزینه بر است، چون اس کیو ال سرور، کل ایندکس را بررسی می‌نماید. نقطه‌ی مقابل و بهینه‌ی آن، Index Seek است که اس کیو ال سرور به صفحه‌ی مورد نظر ایندکسی که به شرایط نزدیک‌تر است، منتقل می‌گردد.

خب چرا اس کیو ال سرور Index Scan را بجای Index Seek انتخاب کرده است؟!

اشکالی در قسمت سمت چپ شکل بالا که به رنگ قرمز نمایش داده شده است، وجود دارد:

Type conversion: Seek Plan for CONVERT_IMPLICIT(nvarchar(20), [Extent1].[PostalZipCode],0)=[@p__linq__0]
[Extent1].[PostalZipCode]  بصورت غیر صریح به (NVARCHAR(20 تبدیل شده است. اما چرا؟
پارامتر کوئری تولید شده‌ی توسط EF از نوع NVARCHAR است و تبدیل نوع NVARCHAR پارامتر کدپستی، که محدوده‌ی اطلاعات بیشتری (Unicode Strings) را نسبت به نوع VARCHAR ستون دارد، به‌دلیل از دست رفتن اطلاعات امکان پذیر نیست. به‌همین جهت برای مقایسه‌ی پارامتر کدپستی با ستون VARCHAR ، اس کیو ال سرور باید هر ردیف ایندکس را از VARCHAR به NVARCHAR تبدیل نماید که منجر به Index Scan می‌شود. اما راه حل بسیار ساده این است که فقط نوع خصیصه را با ستون جدول یکسان کنید.
[Column(TypeName = "varchar")]
public string PostalZipCode { get; set; }

نظرات مطالب
Identity و مباحث مربوطه (قسمت دوم) نحوه بدست آوردن مقادیر Identity
ببین دوست من مطلبتون رو خوندم هم اینو و هم قبلی رو، ازش خوشم اومد اما چیزی راجب درج صریح یا بروز رسانی مقادیر Identity ننوشته بودین. یا اینکه نمیشه در یک جدول دو identity property داشت.
من بلدم با set identity_insert table_name on/off کاری کنم که خودم دستی مقداری را برای خصیصه identity لحاظ کنم. ولی متاسفانه نتونستم مقدار یک ستون با خصیصه Identity رو بروز رسانی (یا همون update) کنم. لطفا بهم بگید که اصلا این کار ممکنه یا من بلد نیستم. البته براساس query زیر بمن SQL Server گفته که نمیشه این ستون را update کرد که ظاهرا هم همین طور(ستون id همانطور که در پیام آمده از نوع identity هست)
update t
set id = new_id
from (select id, row_number() over(order by id) new_id from #temp)t

--Cannot update identity column 'id'.

اصلا اجازه بدین یه جور دیگه سوال رو مطرح کنم من نیاز دارم تمام مقادیر identity رو بروز رسانی کنم تا کاملا پشت سر هم و متوالی بشن این کار را میتونم با یک تابع row_number و یک derived table انجام بدم (اگر بذارن!) همانطور که قبلا نشان دادم، یا با روش زیر این کار را بکنم که البته اجرا نمیشه به این دلیل که در یک جدول نمیشه دو identity property داشت. با فرض اجرا شدن دستور select into باز هم در دستور update با مشکل بر می‌خوردیم (چون نمیشه ستون id را بروز رسانی کرد)
select id, identity(int, 1,1) new_id
into #temptable
from #temp
order by id asc

/*
cannot add identity column, using the SELECT INTO statement, to table '#temptable',
 which already has column 'id' that inherits the identity property.
*/
update t
set id = new_id
from #temp t
join #temptable d
on t.id = d.id;
البته یک راهی برای حل این مساله هست اونم اینه که ابتدا بیاییم تمام داده‌ها جدول را در جدول دیگه ای درج کنیم سپس تمام داده‌های جدول را حذف کنیم سپس داده‌های حذف شده را با id جدید و مرتب شده در جدول اول درج کنیم. به این شکل
declare @t table(id int)

insert into @t
select id from #temp

delete from #temp

set identity_insert #temp on
insert #temp (id)
select row_number() over(order by id) from @t
set identity_insert #temp off
اما مشکلی که وجود داره اینه که اگر جدول ما parent باشه با مشکل واجه میشیم تمام سطرهای جداول child یتیم میشن.

من قصد ندارم صورت مساله نقد و بررسی بشه و اصولی بودن یا صحیح بودنش مورد ارزیابی قرار بگیره فقط برام این یک سوال شده.
مساله عمومی که راجب این ستون وجود داره استفاده کردن از Gap‌های حاصل شده در این ستون برای درج‌های بعدی است. که query آن نیز بسیار ساده و در دسترس است.
آیا شما میدانید که چگونه این مشکل با sequence ای که در نسخه 2012 معرفی شده است حل می‌شود؟
مطالب
first chance exception چیست؟
چند سال قبل یک datapicker تقویم شمسی را برای سیلورلایت تهیه کردم. بعد از آن نسخه‌ی WPF آن هم به پروژه اضافه شد. تا اینکه مدتی قبل مشکل عدم کار کردن آن در یک صفحه‌ی دیالوگ جدید در ویندوز 8 گزارش شد. در حین برطرف کردن این مشکل، مدام سطر ذیل در پنجره‌ی output ویژوال استودیو نمایش داده می‌شد:
 A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
البته برنامه بدون مشکل کار می‌کرد و صفحه‌ی نمایش Exception در VS.NET ظاهر نمی‌شد.


سؤال: first chance exception چیست؟

وقتی استثنایی در یک برنامه رخ می‌دهد، به آن یک first chance exception می‌گویند. این اولین شانسی است که سیستم به شما می‌دهد تا استثنای رخ داده را مدیریت کنید. اگر کدهای برنامه یا ابزاری (یک try/catch یا دیباگر) این اولین شانس را ندید بگیرند، یک second chance exception رخ می‌دهد. این‌جا است که برنامه به احتمال زیاد خاتمه خواهد یافت.
مشاهده‌ی پیام‌های A first chance exception در پنجره‌ی output ویژوال استودیو به این معنا است که استثنایی رخ داده، اما توسط یک استثناءگردان مدیریت شده‌است. بنابراین در اکثر موارد، موضوع خاصی نیست و می‌توان از آن صرفنظر کرد.


سؤال: چگونه می‌توان منشاء اصلی پیام رخ‌دادن یک first chance exception را یافت؟

ویژوال استودیو در پنجره‌ی output، مدام پیام رخ‌دادن first chance exception را نمایش می‌دهد؛ اما واقعا کدام قطعه از کدهای برنامه سبب بروز آن شده‌اند؟ به صورت پیش فرض صفحه‌ی نمایش استثناءها در VS.NET زمانی نمایان می‌شود که استثنای رخ داده، مدیریت نشده باشد. برای فعال سازی نمایش استثناهای مدیریت شده باید تنظیمات ذیل را اعمال کرد:
- به منوی Debug | Exceptions مراجعه کنید.
- گره Common Language Runtime Exceptions را باز کنید.
- سپس گروه System آن‌را نیز باز کنید.
- در اینجا بر اساس نوع استثنایی که در پنجره‌ی output نمایش داده می‌شود، آن استثناء را یافته و Thrown آن‌را انتخاب کنید.


اینبار اگر برنامه را اجرا کنید، دقیقا محلی که سبب بروز استثنای ArgumentOutOfRangeException شده در VS.NET گزارش داده خواهد شد.