diff --git a/src/Directory.Build.props b/src/Directory.Build.props index cd67e553..3c14bb2d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -145,8 +145,8 @@ - - - + + + diff --git a/src/ReactiveUI.Binding.Shared/Expression/ExpressionRewriter.cs b/src/ReactiveUI.Binding.Shared/Expression/ExpressionRewriter.cs index beaa7bb7..aa480239 100644 --- a/src/ReactiveUI.Binding.Shared/Expression/ExpressionRewriter.cs +++ b/src/ReactiveUI.Binding.Shared/Expression/ExpressionRewriter.cs @@ -31,6 +31,8 @@ namespace ReactiveUI.Binding.Expressions; /// is stripped. /// /// +[RequiresUnreferencedCode( + "Expression rewriting uses reflection over runtime types which may be removed by trimming.")] internal sealed class ExpressionRewriter : ExpressionVisitor { /// @@ -141,8 +143,6 @@ internal Expression[] VisitArgumentList(ReadOnlyCollection arguments } /// - [RequiresUnreferencedCode( - "Expression rewriting uses reflection over runtime types which may be removed by trimming.")] protected override Expression VisitBinary(BinaryExpression node) { if (node.Right is not ConstantExpression) @@ -159,8 +159,6 @@ protected override Expression VisitBinary(BinaryExpression node) } /// - [RequiresUnreferencedCode( - "Expression rewriting uses reflection over runtime types which may be removed by trimming.")] protected override Expression VisitUnary(UnaryExpression node) { // Visit() only routes Convert and ArrayLength here, so no fallthrough is needed. @@ -178,8 +176,6 @@ protected override Expression VisitUnary(UnaryExpression node) } /// - [RequiresUnreferencedCode( - "Expression rewriting uses reflection over runtime types which may be removed by trimming.")] protected override Expression VisitMethodCall(MethodCallExpression node) { if (!node.Method.IsSpecialName || !AllConstant(node.Arguments)) diff --git a/src/ReactiveUI.Binding.Shared/Expression/Reflection.cs b/src/ReactiveUI.Binding.Shared/Expression/Reflection.cs index c4a1c2a0..94e4c82b 100644 --- a/src/ReactiveUI.Binding.Shared/Expression/Reflection.cs +++ b/src/ReactiveUI.Binding.Shared/Expression/Reflection.cs @@ -15,17 +15,24 @@ namespace ReactiveUI.Binding.Expressions; /// Helper class for handling reflection and expression-tree related operations. public static class Reflection { - /// Singleton instance of the used for rewriting expression trees. + /// Reported when an expression yields no chain to walk. private const string EmptyExpressionChainMessage = "Expression chain must contain at least one element."; /// The shared rewriter instance used to simplify expressions before inspection. - private static readonly ExpressionRewriter ExpressionRewriterInstance = new(); + /// + /// Built on first use rather than in a static initializer. The rewriter reads runtime types by + /// reflection and says so, and a static constructor has nowhere to carry that annotation. + /// + private static ExpressionRewriter? _expressionRewriter; /// Uses the expression re-writer to simplify the expression down to its simplest expression. /// The expression to rewrite. /// The rewritten expression. + [RequiresUnreferencedCode( + "Expression rewriting uses reflection over runtime types which may be removed by trimming.")] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Expression Rewrite(Expression? expression) => ExpressionRewriterInstance.Visit(expression); + public static Expression Rewrite(Expression? expression) => + (_expressionRewriter ??= new()).Visit(expression); /// Converts an expression that points to a property chain into a dotted path string. /// The expression to generate the property names from.