ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 这是如何导致无限循环的?

2019-05-17 09:03:51  阅读:302  来源: 互联网

标签:c visual-studio-debugging messagebox infinite-loop mutual-recursion


我保留的一些遗留代码卡在无限循环中(因此我自己似乎在一个);但是,我无法弄清楚为什么/如何.

这是应用程序的入口点,它实例化主窗体(frmCentral):

代码展览A.

public static int Main(string [] args)
{
    try
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;

        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalExceptionHandler);

        string name = Assembly.GetExecutingAssembly().GetName().Name;
        MessageBox.Show(string.Format("Executing assembly is {0}", name)); // TODO: Remove after testing <= this one is seen
        IntPtr mutexHandle = CreateMutex(IntPtr.Zero, true, name);
        long error = GetLastError();
        MessageBox.Show(string.Format("Last error int was {0}", error.ToString())); // TODO: Remove after testing <= this one is also seen

        if (error == ERROR_ALREADY_EXISTS)
        {
            ReleaseMutex(mutexHandle);

            IntPtr hWnd = FindWindow("#NETCF_AGL_BASE_", null);
            if ((int) hWnd > 0)
            {
                SetForegroundWindow(hWnd);  
            }
            return 0;
        }

        MessageBox.Show("made it into Main method #4"); // TODO: Remove after testing <= this one is seen

        ReleaseMutex(mutexHandle);

        MessageBox.Show("made it into Main method #5"); // TODO: Remove after testing <= this one is seen

        DeviceInfo devIn = DeviceInfo.GetInstance();

        MessageBox.Show("made it into Main method #6"); // TODO: Remove after testing <= this one is seen

        Wifi.DisableWifi();

        MessageBox.Show("made it into Main method #7"); // TODO: Remove after testing <= this one is seen

        // Instantiate a new instance of Form1.
        frmCentral f1 = new frmCentral();
        f1.Height = devIn.GetScreenHeight();
        f1.Text = SSCS.GetFormTitle("SSCS HHS", "", "");

        MessageBox.Show("made it before Application.Run() in Main method"); // TODO: Remove after testing <= this one is NOT seen
        Application.Run(f1);

        devIn.Close();

        Application.Exit();
        return 0;
    }
    catch(Exception ex)
    {
        SSCS.ExceptionHandler(ex, "Main");
        return 0;
    }
} // Main() method

frmCentral的构造函数然后调用一个名为DBConnection.GetInstance()的单例方法(与glorified相反的是什么?):

CODE EXHIBIT B

public frmCentral()
{
    try
    {
        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();
        MessageBox.Show("made it past InitializeComponent() in frmCentral constructor"); // <= this displays
        devIn = DeviceInfo.GetInstance();
        MessageBox.Show("made it past DeviceInfo.GetInstance() in frmCentral constructor"); // <= this displays
        dbconn = DBConnection.GetInstance();
        MessageBox.Show("made it past DBConnection.GetInstance() in frmCentral constructor");
        WindowState = FormWindowState.Maximized;

        UpdateMenuItemSelectable = false;
        ResetConnectionFetchForm = false;

        AllowNewItems = true;

        listboxWork.Focus();
        MessageBox.Show("made it through frmCentral constructor"); // <= this one does NOT display
    }
    catch (Exception ex)
    {
        SSCS.ExceptionHandler(ex, "frmCentral()");
    }
} // frmCentral Constructor

这是“美化”的单一/种类单身方法:

CODE EXHIBIT C

// Singleton pattern, or at least a derivation thereof
public static DBConnection GetInstance()
{
    MessageBox.Show("made it into DBConnection.GetInstance()");
    try
    {
        if (instance == null)
        {
            MessageBox.Show("made it into DBConnection.GetInstance(); instance was null");
            instance = new DBConnection();
        }
    }
    catch(Exception ex)
    {
        SSCS.ExceptionHandler(ex, "DBConnection.GetInstance");
    }
    return instance;
}

这实例化了DBConnection,因此调用了它的构造函数:

CODE EXHIBIT D

private DBConnection()
{
    try
    {
        // Connection String
        string conStr = "Data Source = " + filename;
        string cmpStr = conStr + ".tmp";
        MessageBox.Show(string.Format("made it into DBConnection constructor. cmpStr == {0}", cmpStr)); // TODO: Comment out or remove
        if (File.Exists(filename+".tmp"))
            File.Delete(filename+".tmp");

        engine = new SqlCeEngine(conStr);
        MessageBox.Show(string.Format("SqlCeEngine created. conStr == {0}", conStr)); // TODO: Comment out or remove

        if (File.Exists(filename))
        {
            MessageBox.Show(string.Format("file {0} exists", filename)); // TODO: Comment out or remove
        }
        else
        {
            // Create the SQL Server CE database
            engine.CreateDatabase();
            MessageBox.Show("Made it past call to engine.CreateDatabase()"); // TODO: Comment out or remove
        }
        engine.Dispose();

        objCon = new SqlCeConnection(conStr);
        MessageBox.Show("Made it past call to new SqlCeConnection(conStr)"); // TODO: Comment out or remove

        objCon.Open();
    }
    catch(Exception ex)
    {
        SSCS.ExceptionHandler(ex, "DBConnection.DBConnection");
    }
}

我从Code Exhibit A看到了* MessageBox.Show()* s(除非另有说明),然后是Code Exhibit B,然后是Code Exhibit C,然后是Code Exhibit D,然后它在C和D之间来回转换“直到奶牛回家.“

我不明白为什么DBConnection构造函数和DBConnection GetInstance()以递归方式相互调用,但是…我在大海捞针中是否有针,或是隐藏在普通视野中的大象,还是……? ?

UPDATE

public static void ExceptionHandler(Exception ex, string location)
{
    try
    {
        MessageBox.Show("Exception: " + ex.Message + "\n\nLocation: " + location, GetFormTitle("SSCS: " + ex.GetType().FullName,"",""));
    }
    catch(Exception exc)
    {
        MessageBox.Show("Exception Handler generated an exception!\n" + exc.Message + "\n\nCalling Location: " + location, GetFormTitle("SSCS: " + exc.GetType().FullName,"",""));
    }
}

更新2

这是更有启发性的晦涩:

public static string GetFormTitle(string formName, string serialNo, string siteNo)
{

    string titleBar = formName == "" ? "SSCS HHS" : formName;

    if((serialNo == ""))
    {
        User person = new User();
        person.getUserFromTable();
        serialNo = person.getSerialNo();
    }

    if (frmCentral.HashSiteMapping.ContainsKey(siteNo))
    {
        siteNo = (string) frmCentral.HashSiteMapping[siteNo];
    }


    if (serialNo != "")
        titleBar += " - " + serialNo + (siteNo == "" ? "" : " Site #" + siteNo);

    return titleBar;
}

更新3

我添加的未捕获的异常代码:

currentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalExceptionHandler);

static void GlobalExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
    Exception e = (Exception)args.ExceptionObject;
    MessageBox.Show(string.Format("GlobalExceptionHandler caught {0}; Compact Framework Version == {1}", e.Message, Environment.Version.ToString()));
}

我还没有看到任何证据表明这个处理程序已经达到(无论如何,到目前为止).

更新4

非常有趣 – 在向GetFormTitle添加MessageBox.Show(或两个)之后:

public static string GetFormTitle(string formName, string serialNo, string siteNo)
{
    MessageBox.Show(string.Format("GetFormTitle() reached. formName == {0}; serialNo == {1}; siteNo == {2}", formName, serialNo, siteNo)); // TODO: Remove after testing
    string titleBar = formName == "" ? "SSCS HHS" : formName;

    if((serialNo == ""))
    {
        User person = new User();
        person.getUserFromTable();
        serialNo = person.getSerialNo();
    }

    if (frmCentral.HashSiteMapping.ContainsKey(siteNo))
    {
        siteNo = (string) frmCentral.HashSiteMapping[siteNo];
    }


    if (serialNo != "")
        titleBar += " - " + serialNo + (siteNo == "" ? "" : " Site #" + siteNo);
    MessageBox.Show(string.Format("titleBar val about to be returned. Val is {0}", titleBar)); // TODO: Remove after testing
    return titleBar;
}

…这些是我现在看到的MessageBox.Show()的序列:

0) Made it into DBConnection.GetInstance() 
1) Made it into DBConnection.GetInstance() instance was null
2) Made it to DBConnection constructor cmpStr == ....
3) Sqlceengine created. conStr == ...
4) File \My Documents\HHSDB.SDF exists
5) Made it past call to new SqlCeConnection(conStr)
6) GetFormTitle() reached. fromName == SSCS:
System.Data.SqlserverCe.SqlCeException; serial No ==; siteNo ==

…接下来是一轮追尾,递归的消息直到我热身启动(我讨厌与Fab 4相矛盾,但与流行的观点相反,幸福绝对不是热情的启动!*)

…所以正好在MessageBox消息显示中,插入了一个异常!全宾夕法尼亚嘻哈(Key Rap)!

* Let's have no attempts at humor revolving around warm booty, now!

这是远程桌面调试的最佳展示,LB2!

解决方法:

这是可能发生的事情(此时是一个理论,直到OP可以确认):

启动问题的事情……

启动无限循环链的问题可能是objCon.Open();在图表D中.连接到数据库可能存在一些问题,而Open()调用应该抛出异常.这当然会被紧跟在该行之后的本地捕获.

本地catch调用SSCS.ExceptionHandler,它显示在Update 1中.它看起来很温和,但是在它中隐藏了罪魁祸首的帮凶,名称GetFormTitle显示在Update 2中.

事情变得更糟……

GetFormTitle有一段非常有趣的代码:

User person = new User();
person.getUserFromTable();

…最有可能是从数据库中检索用户信息的模型(其他地方).

所以创建了无限循环……

好吧,要从数据库中获取用户,需要一个连接,这很可能导致调用DBConnection.GetInstance(),这将转到objCon.Open();它开始新的循环,因此创建了infinite loop(巧妙地,不使用任何语言的内置循环机制,需要及时注意).

确认:

OP:请把非常简单(意思是没有调用GetFormTitle,请)GetFormTitle中的MessageBoxes,如果上述理论是正确的,你会在执行路径中看到它.

标签:c,visual-studio-debugging,messagebox,infinite-loop,mutual-recursion
来源: https://codeday.me/bug/20190517/1119863.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有