چند روز پیش توی یکی از پروژه ها که کار میکردم روش, یک خطای Object reference not set to an instance of an object صادر میشد و خطی که خطا صادر شده بود توی لاگها خط 61 بود. وقتی خط 61 رو چک کردم اصلا امکان خطا وجود نداشت, فقط یک کلاس نمونه سازی شده بود در خط 61. 

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

 توی استک دیدم چند نفر همچین سوالی رو پرسیدن و گفتن که توی Stacktrace مربوط به خطا خط خطا اشتباه نشون داده میشه. یکم رفتم تو فکر :|

بعد باهم پروژه رو ران کردیم روی حالت Debug و خط خطا رو درست نشون میداد. اصلا انتظار نداشتیم. بعد گفتم پروژه رو روی حالت Release ران کنیم ببینیم همون نتیجه رو میده یا نه.

اینبار پروژه رو اجرا کردیم دیدیم که خط خطا اشتباه نشون داده میشه. من که کلا مخم هنگ کرده بود. بعدش مشکل رو حل کردیم و تموم. 

ولی وقتی برگشتم خونه گفتم باید دلیلش رو پیدا کنم. مثال پروژه رو شبیه سازی کردم و توی استک سوال رو پرسیدم. توی حالت Debug خط خطا رو به درستی نشون میداد ولی توی حالت Release خط خطا اشتباه بود. سوالم به این شکل بود:

یه کلاس User دارم:

public class User
{
    public string Name { get; set; }
    public string Family { get; set; }
    public string Type { get; set; }
}

و یه متد DoSomething که شبیه سازی مثال پروژه واقعی بود:

public static void Main()
{
    try
    {
        List<User> users = new List<User>();
        users.Add(new User
        {
            Family = "Zamani",
            Name = "Farhad",
            Type = "ADT"
        });
        DoSomething(users);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.StackTrace);
    }
}
public static void DoSomething(List<User> users)
{
    var adult = users.Where(a =>  // line 34
                                a.Name.ToUpperInvariant() == "Farhad".ToUpperInvariant()
                             && a.Family.ToUpperInvariant() == "Zaman".ToUpperInvariant()
                             ).FirstOrDefault();

    (string name, string type) = GetPassengerInfo(GetType(adult.Type), "Farhad");//line 39

}
private static (string name, string type) GetPassengerInfo(string type, string name)
{
    return (name, type);
}
static string GetType(string type)
{
    string result = string.Empty;
    switch (type)
    {
        case "ADT":
            result = "Adult";
            break;
    }
    return result;
}

وقتی پروژه رو توی حالت Debug اجرا میکنم خط خطا به درستی نشون داده میشه و خط 39 رو نشون میده. ولی وقتی پروژه رو به حالت Release میرم خط خطا به 34 رو نشون میده. 

دلیلش اینه که توی حالت Release و وقتی که پابلیش انجام میدیم, optimizer شروع به کار میکنه و کدهایی که استفاده ای ندارن رو پاک میکنه و یه موضوع هست به اسم Method inlining که خیلی مهمه و تغییرات زیادی ایجاد میکنه تو این حالت و به همین دلیل توی Release امکان این وجود داره که خطی که خطا صادر شده, با سورس کده شما تفاوت داشته باشه.

منابع مرتبط:

:)

Powered by Froala Editor