From 7d35aa8759ed3dd314573b76e91ac73eff128b71 Mon Sep 17 00:00:00 2001 From: Steve Wilkes Date: Sun, 14 Nov 2021 09:57:40 +0000 Subject: [PATCH] Ensuring auto-generated LINQ expression parameter names are valid / Removing redundant anonymous type member specifications in member to value assignments re: #97 --- .../WhenGettingFriendlyTypeNames.cs | 27 ++++++++++++++++++- .../AnonymousTypeNewingTranslation.cs | 18 ++++++++++--- .../Translations/IParameterTranslation.cs | 2 ++ .../Translations/ParameterTranslation.cs | 20 +++++++++++--- 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/ReadableExpressions.UnitTests/Extensions/WhenGettingFriendlyTypeNames.cs b/ReadableExpressions.UnitTests/Extensions/WhenGettingFriendlyTypeNames.cs index 18f775f5..6bc93e1e 100644 --- a/ReadableExpressions.UnitTests/Extensions/WhenGettingFriendlyTypeNames.cs +++ b/ReadableExpressions.UnitTests/Extensions/WhenGettingFriendlyTypeNames.cs @@ -2,6 +2,8 @@ { using System; using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; using Common; using ReadableExpressions.Extensions; #if !NET35 @@ -135,7 +137,7 @@ public void ShouldNameGenericGenericTypeArguments() // See https://github.com/agileobjects/ReadableExpressions/issues/94 [Fact] - public void ShouldNamePartClosedGenericTypeArguments() + public void ShouldNamePartClosedGenericTypeArrays() { var name = typeof(GenericTestHelper<>) .GetField("Keys").FieldType @@ -144,6 +146,29 @@ public void ShouldNamePartClosedGenericTypeArguments() name.ShouldBe("KeyValuePair[]"); } + // See https://github.com/agileobjects/ReadableExpressions/issues/97 + [Fact] + public void ShouldNameLinqExpressionVariables() + { + Expression>> linqQuery = () => + from s in new[] { "1", "2", "3", "4", "5" } + let n = int.Parse(s) + where n > 3 + group s by s into result + select result.Count(); + + const string EXPECTED = @" +() => new[] { ""1"", ""2"", ""3"", ""4"", ""5"" } + .Select(s => new { s, n = int.Parse(s) }) + .Where(_ => _.n > 3) + .GroupBy(_ => _.s, _ => _.s) + .Select(result => result.Count())"; + + var translated = linqQuery.ToReadableString(); + + translated.ShouldBe(EXPECTED.TrimStart()); + } + #region Helper Classes // ReSharper disable once UnusedTypeParameter diff --git a/ReadableExpressions/Translations/AnonymousTypeNewingTranslation.cs b/ReadableExpressions/Translations/AnonymousTypeNewingTranslation.cs index 4b7d7d2c..3929f9ca 100644 --- a/ReadableExpressions/Translations/AnonymousTypeNewingTranslation.cs +++ b/ReadableExpressions/Translations/AnonymousTypeNewingTranslation.cs @@ -97,9 +97,17 @@ public AnonymousTypeInitializerTranslation( ParameterInfo member, ITranslation value) { - _memberName = member.Name; _value = value; + if (value is IParameterTranslation parameter && + parameter.Name == member.Name) + { + _memberName = string.Empty; + TranslationSize = value.TranslationSize; + return; + } + + _memberName = member.Name; TranslationSize = _memberName.Length + 3 + value.TranslationSize; } @@ -117,8 +125,12 @@ public AnonymousTypeInitializerTranslation( public void WriteTo(TranslationWriter writer) { - writer.WriteToTranslation(_memberName); - writer.WriteToTranslation(" = "); + if (_memberName != string.Empty) + { + writer.WriteToTranslation(_memberName); + writer.WriteToTranslation(" = "); + } + _value.WriteTo(writer); } } diff --git a/ReadableExpressions/Translations/IParameterTranslation.cs b/ReadableExpressions/Translations/IParameterTranslation.cs index 7add716c..401d3eb7 100644 --- a/ReadableExpressions/Translations/IParameterTranslation.cs +++ b/ReadableExpressions/Translations/IParameterTranslation.cs @@ -2,6 +2,8 @@ { internal interface IParameterTranslation : ITranslation { + string Name { get; } + void WithTypeNames(ITranslationContext context); void WithoutTypeNames(ITranslationContext context); diff --git a/ReadableExpressions/Translations/ParameterTranslation.cs b/ReadableExpressions/Translations/ParameterTranslation.cs index db36a876..167c9a29 100644 --- a/ReadableExpressions/Translations/ParameterTranslation.cs +++ b/ReadableExpressions/Translations/ParameterTranslation.cs @@ -7,6 +7,7 @@ using System.Linq.Expressions; #endif using Extensions; + using static System.StringComparison; using static Formatting.TokenType; internal static class ParameterTranslation @@ -18,13 +19,22 @@ public static ITranslation For(ParameterExpression parameter, ITranslationContex return new UnnamedParameterTranslation(parameter, context); } + if (parameter.Name.StartsWith("<>", Ordinal)) + { + return new FixedValueTranslation( + ExpressionType.Parameter, + "_", + parameter.Type, + Variable, + context); + } + return new StandardParameterTranslation(parameter, context); } private abstract class ParameterTranslationBase : IParameterTranslation { private readonly ParameterExpression _parameter; - private readonly string _parameterName; private ITranslation _typeNameTranslation; protected ParameterTranslationBase( @@ -33,9 +43,9 @@ protected ParameterTranslationBase( ITranslationContext context) { _parameter = parameter; - _parameterName = parameterName; + Name = parameterName; - TranslationSize = _parameterName.Length; + TranslationSize = Name.Length; FormattingSize = context.GetFormattingSize(Variable); } @@ -47,6 +57,8 @@ protected ParameterTranslationBase( public int FormattingSize { get; private set; } + public string Name { get; } + public void WithTypeNames(ITranslationContext context) { _typeNameTranslation = context.GetTranslationFor(Type); @@ -77,7 +89,7 @@ public void WriteTo(TranslationWriter writer) writer.WriteSpaceToTranslation(); } - writer.WriteToTranslation(_parameterName, Variable); + writer.WriteToTranslation(Name, Variable); } }