【问题标题】:How to get ride of infinite recursion? [closed]如何摆脱无限递归? [关闭]
【发布时间】:2020-06-25 07:30:13
【问题描述】:

我有一个来自客户端的 OAuth2.0 Json 数据。而且我必须将所有数据从特定 API 提取到我的 SQL 数据库。这个 API 有一些验证,比如他们一次只能显示 250 个数据,接下来我们用不同的参数再次运行 API。 像这样的 API 数据结构。

{
  "next": URL or null,                  // URL of the next page (same as the requested URL, but with the page query parameter incremented)
  "previous": URL or null,              // URL of the previous page
  "results": array of result objects    // the results follow the same format as `:endpoint/:id`
}

对于下一个或上一个数据,我们必须运行 URL 所在的上一个或下一个。

我自动将此 API 中的数据导入我的 SQL 数据。但是经过一些循环后我得到了这个错误。

在剩下的数据之后,我无法导入我的 SQL 数据库。 我正在研究 Dr.chrono API 以将他们的数据导入我的系统。 我不明白如何处理这种情况。

代码下方:-

private void recursivemethod(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)
        {


                RestClient client = new RestClient(URL);

                RestRequest request = new RestRequest(Method.GET);
                request.Parameters.Clear();
                client.Timeout = -1;
                request.AddHeader("authorization", "Bearer " + token);
                request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
                request.AddHeader("cache-control", "no-cache");
                IRestResponse response = client.Execute(request);
                ////Using dynamic keyword with JsonConvert.DeserializeObject, here you need to import Newtonsoft.Json  


                dynamic myObject = JsonConvert.DeserializeObject(response.Content);
                if (flag == "patient")
                {
                    PatientMain items = JsonConvert.DeserializeObject<PatientMain>(response.Content);
                    int i = 0;
                    lstarray.Clear();
                    foreach (var type in items.results)
                    {
                        i++;

                        lstarray.Add("INSERT INTO drchrono_patient(id,chart_id,first_name,middle_name,last_name,date_of_birth,gender,social_security_number,race,ethnicity,preferred_language,patient_status,home_phone,cell_phone,office_phone,email,address,city,state,zip_code,doctor,primary_care_physician,date_of_first_appointment,date_of_last_appointment,default_pharmacy,referring_source,copay,updated_at) VALUES ('" + convertQuotes(type.id) + "','" + convertQuotes(type.chart_id) + "','" + convertQuotes(type.first_name) + "','" + convertQuotes(type.middle_name) + "','" + convertQuotes(type.last_name) + "','" + convertQuotes(type.date_of_birth) + "','" + convertQuotes(type.gender) + "','" + convertQuotes(type.social_security_number) + "','" + convertQuotes(type.race) + "','" + convertQuotes(type.ethnicity) + "','" + convertQuotes(type.preferred_language) + "' ,'" + convertQuotes(type.patient_status) + "','" + convertQuotes(type.home_phone) + "','" + convertQuotes(type.cell_phone) + "','" + convertQuotes(type.office_phone) + "','" + convertQuotes(type.email) + "','" + convertQuotes(type.address) + "','" + convertQuotes(type.city) + "','" + convertQuotes(type.state) + "','" + convertQuotes(type.zip_code) + "','" + convertQuotes(type.doctor) + "','" + convertQuotes(type.primary_care_physician) + "','" + convertQuotes(type.date_of_first_appointment) + "','" + convertQuotes(type.date_of_last_appointment) + "','" + convertQuotes(type.default_pharmacy) + "','" + convertQuotes(type.referring_source) + "','" + convertQuotes(type.copay) + "','" + convertQuotes(type.updated_at) + "') ");


                    }
                    string result = dbf.pExecuteQueryList(lstarray);
                    if (items.next != null)
                    {
                        URL = items.next;
                        recursivemethod(lstarray, token, URL, flag, sb);
                    }
                }
}

【问题讨论】:

  • 请分享整个代码
  • 大概你的逻辑中某处有无限递归。异常是否有堆栈跟踪?这将确定递归的路径。
  • @PavelAnikhouski 请检查我的代码。
  • @David 但我不知道 API 中有多少数据。我必须通过 API 导入所有数据。而且他们没有任何其他资源。如果我手动进行,那没有任何意义。但是当我进行自动化时,它会显示异常。我知道我不能运行无限循环和递归。但为此我能做些什么来获取所有数据。
  • @Fildor 使用递归的原因是 API 一次只提供 250 个数据。对于下一个数据,他们在下一个和上一个中提供 API URL,如上所示。如果您有任何想法,请提出建议并点击此处。

标签: c# asp.net api asp.net-web-api chrono


【解决方案1】:

考虑使用循环而不是递归。您可以保持大部分逻辑相同,只需重新构建重复它的方式。让我们首先更改方法签名以返回一个值。像这样的东西应该可以工作:

private string GetItems(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)

在该方法中,不是递归返回自身,而是返回该 URL 值:

foreach (var type in items.results)
{
    // your current loop, though be aware that you should update this to use query parameters
}
return item.next;

(在方法的其他地方你可以默认return null;,这样所有的代码路径都会返回一个值。)

那么从概念上讲,您的循环可能看起来像这样:

var url = "whatever your initial starting URL is";
while (url != null)
{
    url = GetItems(lstarray, token, url, flag, sb);
}

基本上,这里不需要递归。您正在重复一个动作未知的次数,但这个未知的动态值仍然可以用作循环条件,并且不需要递归。

【讨论】:

  • 也许我遗漏了什么,但我认为sb 甚至没有在原始代码中使用?
  • @Fildor:看起来确实如此。我敢打赌,还可以进行许多其他小的改进。我什至不完全喜欢修改lstarray 参数或有时将null 作为魔术值返回的方法的想法,但它是private 的事实至少向我保证了这种混乱被封装了。不过,从逻辑上讲,这至少应该是一个好的开始。
  • 完全同意。
  • @David - 谢谢它的工作。今天学习新事物。 :-)
【解决方案2】:

您有一个StackOverflow exception。来自微软文档:

执行堆栈溢出时抛出的异常,因为它包含太多的嵌套方法调用。

在文档后面

[...] 通常在 非常深 或无限递归 [..]

的情况下

实际上,您的停止条件可能工作正常,只是在execution stack(您的应用程序必须运行的内存量)已满之前永远不会达到。

通常,当应用程序运行时,每个不会再次使用的变量、数据结构、对象都会从内存中删除,并可以用于存储其他内容。

递归的问题是内存不能被清空或优化,直到递归完成,你的内存填满并且在某个时候你用完了。

我不确定递归是不是一个好的选择,你可以简单地做一个循环,这将提高内存效率,允许系统在每次迭代之间清理内存。

如果您需要坚持递归,您应该考虑重新建模您的代码以将所有变量作为reference 传递,否则执行堆栈将填满大量您不需要复制的无用复制数据.

【讨论】:

  • “我不确定递归是不是一个好的选择” 如果你有一点怀疑,它不是最好的选择。 (来自经验和生产代码)不过,在学术环境中,情况可能会有所不同。
  • 我们在工作中使用的规则是:如果它是一个轻量级的树结构(例如菜单、文件指针树等),我们使用递归,否则我们不使用递归。跨度>
  • 在这些情况下你确定,对吧? ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 2018-05-03
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多