
When an include is not surrounded by empty lines, its content is inlined on the same line as the adjacent content. That can lead to broken tags and other display issues. This PR fixes all such includes and introduces a validation step that forbids introducing the same problem again.
96 lines
2.0 KiB
Plaintext
96 lines
2.0 KiB
Plaintext
== Why is this an issue?
|
|
|
|
https://en.wikipedia.org/wiki/Recursion[Recursion] is a technique used to define a problem in terms of the problem itself, usually in terms of a simpler version of the problem itself.
|
|
|
|
For example, the implementation of the generator for the n-th value of the https://en.wikipedia.org/wiki/Fibonacci_sequence[Fibonacci sequence] comes naturally from its mathematical definition, when recursion is used:
|
|
|
|
[source,csharp]
|
|
----
|
|
int NthFibonacciNumber(int n)
|
|
{
|
|
if (n <= 1)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return NthFibonacciNumber(n - 1) + NthFibonacciNumber(n - 2);
|
|
}
|
|
}
|
|
----
|
|
|
|
As opposed to:
|
|
|
|
[source,csharp]
|
|
----
|
|
int NthFibonacciNumber(int n)
|
|
{
|
|
int previous = 0;
|
|
int last = 1;
|
|
for (var i = 0; i < n; i++)
|
|
{
|
|
(previous, last) = (last, last + previous);
|
|
}
|
|
return last;
|
|
}
|
|
----
|
|
|
|
The use of recursion is acceptable in methods, like the one above, where you can break out of it.
|
|
|
|
[source,csharp]
|
|
----
|
|
int NthFibonacciNumber(int n)
|
|
{
|
|
if (n <= 1)
|
|
{
|
|
return 1; // Base case: stop the recursion
|
|
}
|
|
// ...
|
|
}
|
|
----
|
|
|
|
It is also acceptable and makes sense in some type definitions:
|
|
|
|
[source,csharp]
|
|
----
|
|
class Box : IComparable<Box>
|
|
{
|
|
public int CompareTo(Box? other)
|
|
{
|
|
// Compare the two Box instances...
|
|
}
|
|
}
|
|
----
|
|
|
|
With types, some invalid recursive definitions are caught by the compiler:
|
|
|
|
[source,csharp]
|
|
----
|
|
class C2<T> : C2<T> // Error CS0146: Circular base type dependency
|
|
{
|
|
}
|
|
|
|
class C2<T> : C2<C2<T>> // Error CS0146: Circular base type dependency
|
|
{
|
|
}
|
|
----
|
|
|
|
In more complex scenarios, however, the code will compile but execution will result in a https://learn.microsoft.com/en-us/dotnet/api/system.typeloadexception[TypeLoadException] if you try to instantiate the class.
|
|
|
|
[source,csharp]
|
|
----
|
|
class C1<T>
|
|
{
|
|
}
|
|
|
|
class C2<T> : C1<C2<C2<T>>> // Noncompliant
|
|
{
|
|
}
|
|
|
|
var c2 = new C2<int>(); // This would result into a TypeLoadException
|
|
----
|
|
|
|
include::../resources.adoc[]
|
|
|
|
include::../rspecator.adoc[]
|