C# Winform递归循环-方法被反复调用

C# Winform递归循环-方法被反复调用,c#,winforms,C#,Winforms,请随意创建windows窗体应用程序。要再现错误,请禁用网络连接并运行代码。它每1秒尝试重新连接一次。在4-5次尝试后,启用网络连接,并在调试模式下,您将注意到,即使获取产品,Reconnect()方法也会被调用4-5次。获取产品后,为什么它会一次又一次地调用Reconnect()方法 string apiUrl = "https://api.gdax.com/products"; string json; private void Form1_

请随意创建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;
        }
    }

这是因为如果没有网络连接,那么调用API url将无法连接,并且在
catch
块中,您正试图重新连接

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


没有internet连接时。计数变量始终为零。

这里有一个意外循环:

如果
FillProducts
失败,它将调用自己

  • 迭代:FP失败
  • 迭代:FP调用ReconnectOnEx调用FP,再次失败
  • 迭代:FP调用重新连接调用FP调用重新连接
  • n。迭代:。。。。调用成功的FP并返回

    现在,随着每次迭代调用
    重新连接
    ,整个堆栈将展开

    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);
            }
        }
    
    需要考虑的其他几点:

  • 您不应该在GUI线程上执行网络I/O。您的GUI可能会变得无响应。考虑使用异步/等待(任务异步模式)< /P>
  • 捕获异常可能不是最好的主意。您应该捕获可能的最特定异常,并让调用方处理其余异常


  • 这是由于
    中的else部分,如果(count<0)
    你再次调用它,我必须这样做。。不过,它不会出现在这条线上。如果您运行代码,您将看到它调用FillProducts();重新连接();一次又一次,即当没有Internet时,它第一次尝试重新连接的次数您有一个间接递归调用-
    FillProducts()
    调用
    重新连接错误(ex)如果出现调用
    FillProducts()
    的异常。请运行代码并在不使用internet的情况下进行调试,然后在尝试4-5次重新连接后启动internet。请不要停止我正在尝试重新连接的应用程序,但我的问题是,一旦internet恢复,为什么它仍然调用4-5次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);
            }
        }
    
    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;
        }