递归代码很难理解 - 需要简化

jjj*_*jjj -2 c# recursion

我有一个实体,我可以拥有InvoiceLine,然后您可以无限次地信用该发票行.但只有主InvoiceLine才能引用原始实体.

我使用递归来获取原始实体,但代码不是那么可读

private static PermanentPlacement PopulatePermanentPlacement(InvoiceLine invoiceLine)
        {
            PermanentPlacement permanentPlacement;
            var creditReissue = invoiceLine.CreditReissue;
            do
            {
                permanentPlacement = creditReissue.InvoiceLine.PermanentPlacement;
                if (permanentPlacement == null)
                {
                    creditReissue = creditReissue.InvoiceLine.CreditReissue;
                }
            } while(permanentPlacement == null);

            return permanentPlacement;
        }
Run Code Online (Sandbox Code Playgroud)

有什么方法可以让我更可读和简化?

Eri*_*ert 5

我认为RenéVogt的答案显示了简化此代码的最佳方法.但还有其他人.例如,考虑将循环移动到辅助函数:

static IEnumerable<Reissue> CreditReissues(Reissue original)
{
  var current = original;
  while(true) 
  {
    yield return current;
    current = current.InvoiceLine.CreditReissue;
  } 
}
Run Code Online (Sandbox Code Playgroud)

现在你不需要再次编写一个循环来使用无限的信用重发序列:

private static PermanentPlacement PopulatePermanentPlacement(
  InvoiceLine invoiceLine)
{
  return CreditReissues(invoiceLine.CreditReissue)
    .Select(cr => cr.InvoiceLine.PermanentPlacement)
    .First(pp => pp != null);
}
Run Code Online (Sandbox Code Playgroud)

即:采用无限的信用重发序列,将其转换为永久放置的无限序列,并返回序列中的第一个非空信用序列.

注意如何通过将循环更改为一个序列,我们现在可以描述我们想要在序列级别而不是语句和变量级别上执行的操作.

顺便说一句,你说 - 两次 - 你在原始代码中使用递归,但你不是.递归解决方案如下所示:

private static PermanentPlacement PopulatePermanentPlacement(
  InvoiceLine invoiceLine)
{
  return invoiceLine.PermanentPlacement ??
         PopulatePermanentPlacement(
           invoiceLine.CreditReissue.InvoiceLine);
} 
Run Code Online (Sandbox Code Playgroud)

您不应该对可能无限制的循环使用递归解决方案,因为C#不能保证是尾递归的,因此可能会破坏堆栈.