| Severity | Error |
| Reported by | PostSharp |
| Message | Error evaluating the expression "<Expression>": the maximum recursion level is reached. Check whether properties refer to each other in a cycle. |
Cause
The Property elements of a postsharp.config file can refer to other properties with expressions such as {$TracingEnabled}; see Using Expressions in Configuration Files. A property with Deferred="true" keeps its expression and evaluates it every time the property is used, so it can refer to a property that is defined later. When deferred properties refer to each other in a cycle, directly or through other properties, their evaluation never ends. PostSharp stops when the references nest more than 32 levels deep and reports PS0023.
<Expression> is the expression that PostSharp was evaluating when it stopped, and the location of the message is the Property element that contains it, in one of the properties of the cycle.
A property without Deferred="true" is evaluated where it is defined, and a reference to a property that is not defined yet evaluates to an empty string, so a cycle needs at least one deferred property.
PostSharp reports PS0023 while it loads the configuration of the project, so it also reports PS0084, which says that the project could not be initialized.
In the following example, the deferred properties LoggingEnabled and TracingEnabled refer to each other, and OrderLoggingEnabled evaluates them.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
<!-- Each deferred property refers to the other one, so their evaluation never ends. -->
<Property Name="LoggingEnabled" Value="{$TracingEnabled}" Deferred="true" />
<Property Name="TracingEnabled" Value="{$LoggingEnabled}" Deferred="true" />
<Property Name="OrderLoggingEnabled" Value="{$LoggingEnabled}" />
</Project>
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.PS0023_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
public class OrderService
{
[Log]
public void PlaceOrder( string product )
{
Console.WriteLine( $"Order placed for {product}." );
}
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Coffee" );
}
}
error PS0084: The project could not be initialized because of the previous errors.
error PS0023: postsharp.config(4,4): Error evaluating the expression "{$TracingEnabled}": the maximum recursion level is reached. Check whether properties refer to each other in a cycle.
Resolution
Break the cycle: give one of the properties of the cycle a value that does not refer, directly or indirectly, to the property itself. To find the properties of the cycle, start from the Property element at the location of the message and follow its references.
When a property refers to itself to extend a value, for example Value="{$Categories};Orders", remove Deferred="true": the expression is then evaluated where the property is defined, with the value that the property had before.
In the following example, TracingEnabled has a value of its own, and the project builds.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
<!-- TracingEnabled has a value of its own, so the evaluation of LoggingEnabled ends. -->
<Property Name="LoggingEnabled" Value="{$TracingEnabled}" Deferred="true" />
<Property Name="TracingEnabled" Value="true" />
<Property Name="OrderLoggingEnabled" Value="{$LoggingEnabled}" />
</Project>
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.PS0023_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
public class OrderService
{
[Log]
public void PlaceOrder( string product )
{
Console.WriteLine( $"Order placed for {product}." );
}
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Coffee" );
}
}
Entering PlaceOrder.
Order placed for Coffee.
See Also
Other Resources
Using Expressions in Configuration Files
Configuration File Schema Reference
Configuring Projects Using postsharp.config