Winform递归循环 - 一次又一次地调用方法

时间:2017-08-29 11:14:48

标签: c# winforms

请随意创建一个Windows窗体应用程序。要重现错误,请禁用网络连接并运行代码。它会在每1秒后尝试重新连接。在4-5次尝试启用网络连接后,在调试模式下,您会注意到即使提取产品,也会调用Reconnect()方法4-5次。获取产品后,为什么一次又一次地调用Reconnect()方法?

        string apiUrl = "https://api.gdax.com/products";
        string json;

        private void Form1_Load(object sender, EventArgs e)
        {            
            try
            {                
                if (FillProducts()) // product need first
                {
                }
            }
            catch (WebException ex)
            {
                ReconnectOnError(ex);
            }
        }
        private bool FillProducts()
        {
            bool isDone = false;
            try
            {
                json = GetGDXJSONData(apiUrl);
                JsonSerializer serializer = new JsonSerializer();
                DataTable dt = (System.Data.DataTable)Newtonsoft.Json.JsonConvert.DeserializeObject(json, (typeof(System.Data.DataTable)));

                count = dt.Rows.Count;

                if (count > 0)
                    isDone = true;
            }
            catch (Exception ex)
            {               
                isDone = false;
                ReconnectOnError(ex);
            }
            return isDone;
        }

        int count = 0;
        private void ReconnectOnError(Exception errorMessage)
        {
            try
            {
                Thread.Sleep(1000);
                if (count < 1)
                {
                    FillProducts();     // it comes on this point again and again even the count is greater than 1
                    Reconnect();
                }
                else
                {
                    Reconnect();
                }
            }
            catch (WebException ex)
            {
                ReconnectOnError(ex);
            }
        }

        private void Reconnect()
        {
            // why this is called the number of times the attempt was made to fill the products?
        }      

        private string GetGDXJSONData(string apiUrl)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl);

            request.Method = "GET";
            request.ContentType = "application/json";
            request.UserAgent = "gdax-node-client";
            request.Accept = "application/json";

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            return responseString;
        }
    }

编辑 - 这是一个示例代码,一旦获取产品,我在Reconnect()方法中做了很多事情。 此外,如果在获取产品后发生错误,则不要获取产品,只需调用Reconnect()方法,这就是其他原因。

Edit2 - 请不要仅仅通过查看代码来回复。如果您已经创建了一个表单并自己运行并且可以自己查看错误,那么请告知如何解决此问题。

更新 - 我知道我进入了无限次迭代。我试过这个,现在它起作用了:

    string apiUrl = "https://api.gdax.com/products";
    string json;

    private void Form1_Load(object sender, EventArgs e)
    {
        if (FillProducts()) // product need first
        {
        }
    }

    bool isOk = false;
    private string GetGDAXProducts()
    {
        try
        {
            json = GetGDXJSONData(apiUrl);
            return json;
        }
        catch (Exception ex)
        {               
            return "-1";
        }
    }

    int count = 0;
    private bool FillProducts()
    {
        bool isDone = false;
        string retVal = GetGDAXProducts();

        while (retVal == "-1")
        {
            retVal = GetGDAXProducts();
        }

        if (retVal != "-1")
        {
            JsonSerializer serializer = new JsonSerializer();
            DataTable dt = (System.Data.DataTable)Newtonsoft.Json.JsonConvert.DeserializeObject(json, (typeof(System.Data.DataTable)));

            count = dt.Rows.Count;

            if (count > 0)
                isDone = true;
        }

        return isDone;
    }

    private string GetGDXJSONData(string apiUrl)
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl);

        request.Method = "GET";
        request.ContentType = "application/json";
        request.UserAgent = "gdax-node-client";
        request.Accept = "application/json";

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

        return responseString;
    }

3 个答案:

答案 0 :(得分:1)

这是因为如果没有网络连接,那么调用API网址无法连接,并且在catch阻止您尝试重新连接

        catch (Exception ex)
        {               
            isDone = false;
            ReconnectOnError(ex);
        }

答案 1 :(得分:1)

你在这里有一个无意的循环:

如果FillProducts失败,它会自行调用......

  1. 迭代:FP失败
  2. 迭代:FP调用ReconnectOnEx调用FP,再次失败
  3. 迭代:FP调用ReconnectOnEx调用FP调用ReconnectOnEx ...
  4. <磷>氮。迭代:....调用FP取得并返回

    现在整个堆栈将在每次调用Reconnect时展开。

    private bool FillProducts()
        {
            bool isDone = false;
            try
            {
                /* ... Fails if no connection ... */
            }
            catch (Exception ex)
            {               
                isDone = false;
                ReconnectOnError(ex); // ==> BLOCKS !!
            }
            return isDone;
        }
    
        int count = 0;
        private void ReconnectOnError(Exception errorMessage)
        {
            try
            {
                Thread.Sleep(1000);
                if (count < 1)
                {
                    FillProducts();     // <== Will result in another call to this method. Returns on 1st Succeeding call to FillProducts.
                    Reconnect();        // <== Will be called as soon as FillProducts returns.
                }
                else
                {
                    Reconnect();
                }
            }
            catch (WebException ex)
            {
                ReconnectOnError(ex);
            }
        }
    

    为避免这种情况,您可以将“重试”逻辑移动到FillProducts方法中:

    private bool FillProducts()
        {
            // To prevent waiting forever ...
            int retryCount = 10;
    
            bool isDone = false;
            while ( !isDone && (retryCount-- > 0) )
            {
                try
                {
                    /* ... Fails if no connection ... */
    
                    // OnSuccess=>
                    isDone = true; // will break the loop.
                }
                catch (Exception ex) // You should actually catch a more specific Exception here
                                     // ... but that's a different question.
                {               
                    isDone = false;
                    // Just omit this! >>> ReconnectOnError(ex); // ==> BLOCKS !!
                    // If you want, you can add a little delay here ...
                    Thread.Sleep(1000);
                    // From your code, I guess this has to be called on failure ...
                    Reconnect();
                }
            }
            return isDone;
        }
    

    要考虑的其他几点:

    1. 您不应该在GUI线程上进行网络I / O.您的GUI可能会无响应。考虑使用async / await(任务异步模式)

    2. 捕捉Exception可能不是最好的主意。您应该捕捉到最具体的例外情况,并让其余部分由调用者处理。

答案 2 :(得分:0)

enter image description here

当没有互联网连接时.Count变量始终为零。