From f2a059e34b3b43f3770fb8c07126a6560c72f476 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 20 Oct 2022 18:18:14 +0200 Subject: [PATCH 1/9] DefaultDynamicLinqCustomTypeProvider --- src/Directory.Build.props | 2 +- .../AbstractDynamicLinqCustomTypeProvider.cs | 21 +++++++++---------- .../DefaultDynamicLinqCustomTypeProvider.cs | 12 +++++------ .../IDynamicLinqCustomTypeProvider.cs | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 622dd61d..b4e615fc 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ Copyright © ZZZ Projects en-us true - latest + 10 enable logo.png Apache-2.0 diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs index ec367fd4..811b7d10 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Dynamic.Core.Validation; using System.Reflection; @@ -15,7 +14,7 @@ public abstract class AbstractDynamicLinqCustomTypeProvider /// /// The assemblies to process. /// - protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); #if !NET35 @@ -30,7 +29,7 @@ protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute([NotNull /// The assemblies to inspect. /// The typename to resolve. /// A resolved or null when not found. - protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull] string typeName) + protected Type? ResolveType(IEnumerable assemblies, string typeName) { Check.NotNull(assemblies, nameof(assemblies)); Check.NotEmpty(typeName, nameof(typeName)); @@ -53,19 +52,19 @@ protected Type ResolveType([NotNull] IEnumerable assemblies, [NotNull] /// The assemblies to inspect. /// The simple typename to resolve. /// A resolved or null when not found. - protected Type ResolveTypeBySimpleName([NotNull] IEnumerable assemblies, [NotNull] string simpleTypeName) + protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) { Check.NotNull(assemblies, nameof(assemblies)); Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); foreach (var assembly in assemblies) { - var fullNames = assembly.GetTypes().Select(t => t.FullName).Distinct(); + var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); if (firstMatchingFullname != null) { - Type resolvedType = assembly.GetType(firstMatchingFullname, false, true); + var resolvedType = assembly.GetType(firstMatchingFullname, false, true); if (resolvedType != null) { return resolvedType; @@ -82,13 +81,13 @@ protected Type ResolveTypeBySimpleName([NotNull] IEnumerable assemblie /// /// The assemblies to process. /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); foreach (var assembly in assemblies) { - Type[] definedTypes = null; + Type[]? definedTypes = null; try { @@ -118,13 +117,13 @@ protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNul /// /// The assemblies to process. /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute([NotNull] IEnumerable assemblies) + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) { Check.NotNull(assemblies, nameof(assemblies)); foreach (var assembly in assemblies.Where(a => !a.GlobalAssemblyCache)) // Skip System DLL's { - Type[] definedTypes = null; + Type[]? definedTypes = null; try { diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs index 859e6d97..e6fc9430 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs @@ -6,7 +6,7 @@ namespace System.Linq.Dynamic.Core.CustomTypeProviders { /// - /// The default implementation for . + /// The default implementation for . /// /// Scans the current AppDomain for all types marked with , and adds them as custom Dynamic Link types. /// @@ -19,8 +19,8 @@ public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTyp private readonly IAssemblyHelper _assemblyHelper = new DefaultAssemblyHelper(); private readonly bool _cacheCustomTypes; - private HashSet _cachedCustomTypes; - private Dictionary> _cachedExtensionMethods; + private HashSet? _cachedCustomTypes; + private Dictionary>? _cachedExtensionMethods; /// /// Initializes a new instance of the class. @@ -64,7 +64,7 @@ public Dictionary> GetExtensionMethods() } /// - public Type ResolveType(string typeName) + public Type? ResolveType(string typeName) { Check.NotEmpty(typeName, nameof(typeName)); @@ -73,7 +73,7 @@ public Type ResolveType(string typeName) } /// - public Type ResolveTypeBySimpleName(string simpleTypeName) + public Type? ResolveTypeBySimpleName(string simpleTypeName) { Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); @@ -106,4 +106,4 @@ private Dictionary> GetExtensionMethodsInternal() return list.GroupBy(x => x.Item1, tuple => tuple.Item2).ToDictionary(key => key.Key, methods => methods.ToList()); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs index 1ccd8800..27264fa3 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs @@ -26,7 +26,7 @@ public interface IDynamicLinqCustomTypeProvider /// /// The typename to resolve. /// A resolved or null when not found. - Type ResolveType([NotNull] string typeName); + Type ResolveType(string typeName); /// /// Resolve any type by the simple name which is registered in the current application domain. From e367293330f608f7fde105362bfdaf87d08e3c17 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 20 Oct 2022 21:50:38 +0200 Subject: [PATCH 2/9] . --- .../DynamicExpressionParser.cs | 21 ++++++++++--------- .../Parser/ConstantExpressionHelper.cs | 6 +++--- .../Parser/ExpressionParser.cs | 14 ++++++------- .../Parser/NumberParser.cs | 19 ++++++++--------- .../System.Linq.Dynamic.Core.Tests.csproj | 1 + 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index 02e286cb..934d0eab 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -21,7 +21,7 @@ public static class DynamicExpressionParser /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -41,7 +41,7 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -60,7 +60,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -76,8 +76,9 @@ public static Expression> ParseLambda([CanBeNull] Parsing /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -92,7 +93,7 @@ public static Expression> ParseLambda([NotNull] Type dele /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { return ParseLambda(null, parsingConfig, createParameterCtor, parameters, resultType, expression, values); } @@ -109,14 +110,14 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { - LambdaExpression lambdaExpression = null; - Check.NotNull(parameters, nameof(parameters)); Check.HasNoNulls(parameters, nameof(parameters)); Check.NotEmpty(expression, nameof(expression)); + LambdaExpression? lambdaExpression = null; + var parser = new ExpressionParser(parameters, expression, values, parsingConfig); var parsedExpression = parser.Parse(resultType, createParameterCtor); @@ -131,7 +132,7 @@ public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBe lambdaExpression = Expression.Lambda(parsedExpression, new[] { newParameterExpression }); } else - { + { lambdaExpression = Expression.Lambda(delegateType, parsedExpression, new[] { newParameterExpression }); } } @@ -161,7 +162,7 @@ public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBe /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs index 3c0efe7f..60ef44f4 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs @@ -5,7 +5,7 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class ConstantExpressionHelper { - private static readonly ConcurrentDictionary Expressions = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Expressions = new ConcurrentDictionary(); private static readonly ConcurrentDictionary Literals = new ConcurrentDictionary(); public static bool TryGetText(Expression expression, out string text) @@ -13,7 +13,7 @@ public static bool TryGetText(Expression expression, out string text) return Literals.TryGetValue(expression, out text); } - public static Expression CreateLiteral(object value, string text) + public static Expression CreateLiteral(object? value, string text) { if (!Expressions.ContainsKey(value)) { @@ -26,4 +26,4 @@ public static Expression CreateLiteral(object value, string text) return Expressions[value]; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 0cca1657..204d9638 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -10,7 +10,6 @@ using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; using System.Reflection; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { @@ -38,8 +37,8 @@ public class ExpressionParser private IDictionary _externals; private ParameterExpression _it; private ParameterExpression _parent; - private ParameterExpression _root; - private Type _resultType; + private ParameterExpression? _root; + private Type? _resultType; private bool _createParameterCtor; /// @@ -63,7 +62,7 @@ public class ExpressionParser /// The expression. /// The values. /// The parsing configuration. - public ExpressionParser([CanBeNull] ParameterExpression[] parameters, [NotNull] string expression, [CanBeNull] object[] values, [CanBeNull] ParsingConfig parsingConfig) + public ExpressionParser(ParameterExpression[]? parameters, string expression, object[]? values, ParsingConfig? parsingConfig) { Check.NotEmpty(expression, nameof(expression)); @@ -145,7 +144,7 @@ private void AddSymbol(string name, object value) /// Type of the result. /// if set to true [create parameter ctor]. /// Expression - public Expression Parse([CanBeNull] Type resultType, bool createParameterCtor = true) + public Expression Parse(Type? resultType, bool createParameterCtor = true) { _resultType = resultType; _createParameterCtor = createParameterCtor; @@ -355,7 +354,7 @@ Expression ParseIn() var args = new[] { left }; - Expression nullExpressionReference = null; + Expression? nullExpressionReference = null; if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out MethodBase containsSignature) != 1) { throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray())); @@ -440,7 +439,7 @@ Expression ParseComparisonOperator() _textParser.CurrentToken.Id == TokenId.GreaterThan || _textParser.CurrentToken.Id == TokenId.GreaterThanEqual || _textParser.CurrentToken.Id == TokenId.LessThan || _textParser.CurrentToken.Id == TokenId.LessThanEqual) { - ConstantExpression constantExpr; + ConstantExpression? constantExpr; TypeConverter typeConverter; Token op = _textParser.CurrentToken; _textParser.NextToken(); @@ -517,7 +516,6 @@ Expression ParseComparisonOperator() } } - if (!typesAreSameAndImplementCorrectInterface) { if ((TypeHelper.IsClass(left.Type) || TypeHelper.IsStruct(left.Type)) && right is ConstantExpression) diff --git a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs index fe15bcc2..8efa9cd6 100644 --- a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Globalization; +using System.Globalization; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; @@ -24,7 +23,7 @@ public class NumberParser /// Initializes a new instance of the class. /// /// The ParsingConfig. - public NumberParser([CanBeNull] ParsingConfig config) + public NumberParser(ParsingConfig? config) { _culture = config?.NumberParseCulture ?? CultureInfo.InvariantCulture; } @@ -44,7 +43,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) var isBinary = text.StartsWith(isNegative ? "-0b" : "0b", StringComparison.OrdinalIgnoreCase); var qualifiers = isHexadecimal ? QualifiersHex : Qualifiers; - string qualifier = null; + string? qualifier = null; if (qualifiers.Contains(last)) { int pos = text.Length - 1, count = 0; @@ -74,7 +73,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) throw new ParseException(string.Format(_culture, Res.InvalidIntegerLiteral, text), tokenPosition); } - if (!string.IsNullOrEmpty(qualifier)) + if (!string.IsNullOrEmpty(qualifier) && qualifier!.Length > 0) { if (qualifier == "U" || qualifier == "u") { @@ -132,7 +131,7 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) value = -value; } - if (!string.IsNullOrEmpty(qualifier)) + if (!string.IsNullOrEmpty(qualifier) && qualifier!.Length > 0) { if (qualifier == "L" || qualifier == "l") { @@ -185,10 +184,10 @@ public Expression ParseRealLiteral(string text, char qualifier, bool stripQualif /// The text. /// The type. /// The result. - public bool TryParseNumber(string text, Type type, out object result) + public bool TryParseNumber(string text, Type type, out object? result) { result = ParseNumber(text, type); - return type != null; + return result != null; } /// @@ -196,7 +195,7 @@ public bool TryParseNumber(string text, Type type, out object result) /// /// The text. /// The type. - public object ParseNumber(string text, Type type) + public object? ParseNumber(string text, Type type) { try { @@ -297,4 +296,4 @@ private Expression ParseAsBinary(int tokenPosition, string text, bool isNegative throw new ParseException(string.Format(_culture, Res.InvalidBinaryIntegerLiteral, text), tokenPosition); } } -} +} \ No newline at end of file diff --git a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj index 9cef8bb9..a4473c01 100644 --- a/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj +++ b/test/System.Linq.Dynamic.Core.Tests/System.Linq.Dynamic.Core.Tests.csproj @@ -5,6 +5,7 @@ System.Linq.Dynamic.Core.Tests full True + 10 ../../src/System.Linq.Dynamic.Core/System.Linq.Dynamic.Core.snk {912FBF24-3CAE-4A50-B5EA-E525B9FAEC80} From b65732884bc4117d1ad1456d02efae7c91817bc9 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Thu, 20 Oct 2022 22:17:25 +0200 Subject: [PATCH 3/9] . --- System.Linq.Dynamic.Core.sln.DotSettings | 3 +- .../DynamicExpressionParser.cs | 56 ++++++++++++------- .../Parser/ExpressionPromoter.cs | 10 ++-- .../Parser/IExpressionPromoter.cs | 8 +-- .../Parser/SupportedMethods/MethodFinder.cs | 22 ++++---- .../Parser/TypeHelper.cs | 13 +++-- 6 files changed, 65 insertions(+), 47 deletions(-) diff --git a/System.Linq.Dynamic.Core.sln.DotSettings b/System.Linq.Dynamic.Core.sln.DotSettings index 40a1a991..397fb4cf 100644 --- a/System.Linq.Dynamic.Core.sln.DotSettings +++ b/System.Linq.Dynamic.Core.sln.DotSettings @@ -2,4 +2,5 @@ EF UTC WASM - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index 934d0eab..2274783a 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -116,12 +116,11 @@ public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? pa Check.HasNoNulls(parameters, nameof(parameters)); Check.NotEmpty(expression, nameof(expression)); - LambdaExpression? lambdaExpression = null; - var parser = new ExpressionParser(parameters, expression, values, parsingConfig); var parsedExpression = parser.Parse(resultType, createParameterCtor); + LambdaExpression lambdaExpression; if (parsingConfig != null && parsingConfig.RenameParameterExpression && parameters.Length == 1) { var renamer = new ParameterExpressionRenamer(parser.LastLambdaItName); @@ -179,8 +178,10 @@ public static Expression> ParseLambda(ParsingConfig? pars /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } @@ -194,7 +195,7 @@ public static Expression> ParseLambda([NotNull] Type dele /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -213,7 +214,7 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -232,8 +233,9 @@ public static Expression> ParseLambda([CanBeNull] P /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); Check.NotEmpty(expression, nameof(expression)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, new[] { ParameterExpressionHelper.CreateParameterExpression(typeof(T), string.Empty, parsingConfig?.RenameEmptyParameterExpressionNames ?? false) }, typeof(TResult), expression, values); @@ -248,7 +250,7 @@ public static Expression> ParseLambda([NotNull] Typ /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object[] values) { return ParseLambda(parsingConfig, true, resultType, expression, values); } @@ -263,8 +265,10 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, parsingConfig, true, resultType, expression, values); } @@ -276,7 +280,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? resultType, string expression, params object[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -301,8 +305,10 @@ public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object[] values) { + Check.NotNull(itType, nameof(itType)); + return ParseLambda(true, itType, resultType, expression, values); } @@ -316,8 +322,10 @@ public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Ty /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object[] values) { + Check.NotNull(itType, nameof(itType)); + return ParseLambda(parsingConfig, true, itType, resultType, expression, values); } @@ -332,8 +340,11 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + Check.NotNull(itType, nameof(itType)); + return ParseLambda(delegateType, parsingConfig, true, itType, resultType, expression, values); } @@ -348,7 +359,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -368,8 +379,9 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -385,7 +397,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { return ParseLambda(null, true, parameters, resultType, expression, values); } @@ -400,8 +412,10 @@ public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] param /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, null, true, parameters, resultType, expression, values); } @@ -415,7 +429,7 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [NotNull /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { return ParseLambda(parsingConfig, true, parameters, resultType, expression, values); } @@ -431,8 +445,10 @@ public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConf /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { + Check.NotNull(delegateType, nameof(delegateType)); + return ParseLambda(delegateType, parsingConfig, true, parameters, resultType, expression, values); } @@ -446,9 +462,9 @@ public static LambdaExpression ParseLambda([NotNull] Type delegateType, [CanBeNu /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) { return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs index f5632b16..ca90207b 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs @@ -19,8 +19,8 @@ public ExpressionPromoter(ParsingConfig config) _numberParser = new NumberParser(config); } - /// - public virtual Expression Promote(Expression expr, Type type, bool exact, bool convertExpr) + /// + public virtual Expression? Promote(Expression expr, Type type, bool exact, bool convertExpr) { if (expr.Type == type || type.IsGenericParameter) { @@ -41,7 +41,7 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c if (ConstantExpressionHelper.TryGetText(ce, out string text)) { Type target = TypeHelper.GetNonNullableType(type); - object value = null; + object? value = null; #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) switch (Type.GetTypeCode(ce.Type)) @@ -55,7 +55,7 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c // Make sure an enum value stays an enum value if (target.IsEnum) { - value = Enum.ToObject(target, value); + value = Enum.ToObject(target, value!); } break; @@ -121,4 +121,4 @@ public virtual Expression Promote(Expression expr, Type type, bool exact, bool c return null; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs index 6ec7dd886..29d8ba7f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionPromoter.cs @@ -13,10 +13,10 @@ public interface IExpressionPromoter /// Promote an expression /// /// Source expression - /// Destionation data type to promote + /// Destination data type to promote /// If the match must be exact /// Convert expression - /// The promoted - Expression Promote(Expression expr, Type type, bool exact, bool convertExpr); + /// The promoted or null. + Expression? Promote(Expression expr, Type type, bool exact, bool convertExpr); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index cdfcf7a7..d1c7339c 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -17,7 +17,7 @@ public MethodFinder(ParsingConfig parsingConfig) _parsingConfig = parsingConfig; } - public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expression instance, ref Expression[] args) + public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expression? instance, ref Expression[] args) { // NOTE: `instance` is not passed by ref in the method signature by design. The ContainsMethod should not change the instance. // However, args by reference is required for backward compatibility (removing "ref" will break some tests) @@ -25,7 +25,7 @@ public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expr return FindMethod(type, methodName, staticAccess, ref instance, ref args, out _) == 1; } - public int FindMethod(Type type, string methodName, bool staticAccess, ref Expression instance, ref Expression[] args, out MethodBase method) + public int FindMethod(Type type, string methodName, bool staticAccess, ref Expression? instance, ref Expression[] args, out MethodBase? method) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); @@ -82,7 +82,7 @@ public int FindMethod(Type type, string methodName, bool staticAccess, ref Expre return 0; } - public int FindBestMethodBasedOnArguments(IEnumerable methods, ref Expression[] args, out MethodBase method) + public int FindBestMethodBasedOnArguments(IEnumerable methods, ref Expression[] args, out MethodBase? method) { // Passing args by reference is now required with the params array support. var inlineArgs = args; @@ -124,7 +124,7 @@ public int FindBestMethodBasedOnArguments(IEnumerable methods, ref E return applicable.Length; } - public int FindIndexer(Type type, Expression[] args, out MethodBase method) + public int FindIndexer(Type type, Expression[] args, out MethodBase? method) { foreach (Type t in SelfAndBaseTypes(type)) { @@ -179,19 +179,19 @@ bool IsApplicable(MethodData method, Expression[] args) else { var paramType = method.Parameters.Last().ParameterType; - var paramElementType = paramType.GetElementType(); + var paramElementType = paramType.GetElementType()!; var arrayInitializerExpressions = new List(); for (int j = method.Parameters.Length - 1; j < args.Length; j++) { - Expression promoted = _parsingConfig.ExpressionPromoter.Promote(args[j], paramElementType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); - if (promoted == null) + var promotedExpression = _parsingConfig.ExpressionPromoter.Promote(args[j], paramElementType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); + if (promotedExpression == null) { return false; } - arrayInitializerExpressions.Add(promoted); + arrayInitializerExpressions.Add(promotedExpression); } var paramExpression = Expression.NewArrayInit(paramElementType, arrayInitializerExpressions); @@ -207,12 +207,12 @@ bool IsApplicable(MethodData method, Expression[] args) return false; } - Expression promoted = _parsingConfig.ExpressionPromoter.Promote(args[i], pi.ParameterType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); - if (promoted == null) + var promotedExpression = _parsingConfig.ExpressionPromoter.Promote(args[i], pi.ParameterType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures)); + if (promotedExpression == null) { return false; } - promotedArgs[i] = promoted; + promotedArgs[i] = promotedExpression; } } diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index 22e50778..a16465c3 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -6,7 +6,7 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class TypeHelper { - public static Type FindGenericType(Type generic, Type type) + public static Type? FindGenericType(Type generic, Type type) { while (type != null && type != typeof(object)) { @@ -19,10 +19,10 @@ public static Type FindGenericType(Type generic, Type type) { foreach (Type interfaceType in type.GetInterfaces()) { - Type found = FindGenericType(generic, interfaceType); - if (found != null) + var foundType = FindGenericType(generic, interfaceType); + if (foundType != null) { - return found; + return foundType; } } } @@ -404,7 +404,7 @@ public static Type GetUnderlyingType(Type type) Type[] genericTypeArguments = type.GetGenericArguments(); if (genericTypeArguments.Any()) { - var outerType = GetUnderlyingType(genericTypeArguments.LastOrDefault()); + var outerType = GetUnderlyingType(genericTypeArguments.LastOrDefault()!); return Nullable.GetUnderlyingType(type) == outerType ? type : outerType; } @@ -443,7 +443,7 @@ private static void AddInterface(List types, Type type) } } - public static object ParseEnum(string value, Type type) + public static object? ParseEnum(string value, Type type) { if (type.GetTypeInfo().IsEnum && Enum.IsDefined(type, value)) { @@ -458,6 +458,7 @@ public static bool IsDictionary(Type type) return FindGenericType(typeof(IDictionary<,>), type) != null || #if NET35 || NET40 + // ReSharper disable once RedundantLogicalConditionalExpressionOperand false; #else FindGenericType(typeof(IReadOnlyDictionary<,>), type) != null; From 424f74be297f5facc207faee3401f94c72b0e439 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 21 Oct 2022 14:00:57 +0200 Subject: [PATCH 4/9] . --- .../IDynamicLinqCustomTypeProvider.cs | 6 +- .../DynamicExpressionParser.cs | 50 +++---- .../Parser/ExpressionHelper.cs | 24 ++-- .../Parser/ExpressionParser.cs | 129 +++++++++--------- .../Parser/IExpressionHelper.cs | 2 +- .../Parser/ITypeFinder.cs | 5 +- .../Parser/PredefinedTypesHelper.cs | 2 +- .../Parser/SupportedMethods/MethodFinder.cs | 10 +- .../Parser/TypeFinder.cs | 27 ++-- .../Parser/TypeHelper.cs | 10 +- 10 files changed, 131 insertions(+), 134 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs index 27264fa3..4d950612 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/IDynamicLinqCustomTypeProvider.cs @@ -26,13 +26,13 @@ public interface IDynamicLinqCustomTypeProvider /// /// The typename to resolve. /// A resolved or null when not found. - Type ResolveType(string typeName); + Type? ResolveType(string typeName); /// /// Resolve any type by the simple name which is registered in the current application domain. /// /// The typename to resolve. /// A resolved or null when not found. - Type ResolveTypeBySimpleName([NotNull] string simpleTypeName); + Type? ResolveTypeBySimpleName(string simpleTypeName); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index 2274783a..df051747 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -21,7 +21,7 @@ public static class DynamicExpressionParser /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[]values) { Check.NotEmpty(expression, nameof(expression)); @@ -41,7 +41,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[]values) { Check.NotEmpty(expression, nameof(expression)); @@ -60,7 +60,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -76,7 +76,7 @@ public static Expression> ParseLambda(ParsingConfig? pars /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, typeof(TResult), expression, values); @@ -93,7 +93,7 @@ public static Expression> ParseLambda(Type delegateType, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { return ParseLambda(null, parsingConfig, createParameterCtor, parameters, resultType, expression, values); } @@ -110,7 +110,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { Check.NotNull(parameters, nameof(parameters)); Check.HasNoNulls(parameters, nameof(parameters)); @@ -161,7 +161,7 @@ public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? pa /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[]values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } @@ -178,7 +178,7 @@ public static Expression> ParseLambda(ParsingConfig? pars /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -195,7 +195,7 @@ public static Expression> ParseLambda(Type delegateType, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -214,7 +214,7 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) { Check.NotEmpty(expression, nameof(expression)); @@ -233,7 +233,7 @@ public static Expression> ParseLambda(ParsingConfig /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object[] values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotEmpty(expression, nameof(expression)); @@ -250,7 +250,7 @@ public static Expression> ParseLambda(Type delegate /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[]values) { return ParseLambda(parsingConfig, true, resultType, expression, values); } @@ -265,7 +265,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? r /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -280,7 +280,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type? resultType, string expression, params object?[]values) { Check.NotEmpty(expression, nameof(expression)); @@ -289,7 +289,7 @@ public static LambdaExpression ParseLambda(Type? resultType, string expression, // DO NOT ADD: It create ambiguous method error //[PublicAPI] - //public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values) + //public static LambdaExpression ParseLambda([CanBeNull] Type delegateType, [CanBeNull] Type resultType, [NotNull] string expression, params object?[]values) //{ // Check.NotEmpty(expression, nameof(expression)); @@ -305,7 +305,7 @@ public static LambdaExpression ParseLambda(Type? resultType, string expression, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(itType, nameof(itType)); @@ -322,7 +322,7 @@ public static LambdaExpression ParseLambda(Type itType, Type? resultType, string /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(itType, nameof(itType)); @@ -340,7 +340,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type it /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); @@ -359,7 +359,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -379,7 +379,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); @@ -397,7 +397,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { return ParseLambda(null, true, parameters, resultType, expression, values); } @@ -412,7 +412,7 @@ public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Typ /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -429,7 +429,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParameterExpressio /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { return ParseLambda(parsingConfig, true, parameters, resultType, expression, values); } @@ -445,7 +445,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Paramet /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -462,7 +462,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object[] values) + public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) { return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values); } diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 3074a326..5d97093c 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -4,7 +4,6 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { @@ -13,7 +12,7 @@ internal class ExpressionHelper : IExpressionHelper private readonly IConstantExpressionWrapper _constantExpressionWrapper = new ConstantExpressionWrapper(); private readonly ParsingConfig _parsingConfig; - internal ExpressionHelper([NotNull] ParsingConfig parsingConfig) + internal ExpressionHelper(ParsingConfig parsingConfig) { Check.NotNull(parsingConfig, nameof(parsingConfig)); @@ -196,7 +195,7 @@ public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression ri } } - public Expression OptimizeStringForEqualityIfPossible(string text, Type type) + public Expression? OptimizeStringForEqualityIfPossible(string text, Type type) { if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) { @@ -243,7 +242,7 @@ private MethodInfo GetStaticMethod(string methodName, Expression left, Expressio var methodInfo = left.Type.GetMethod(methodName, new[] { left.Type, right.Type }); if (methodInfo == null) { - methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type }); + methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type })!; } return methodInfo; @@ -292,7 +291,7 @@ public bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, boo return true; } - public bool ExpressionQualifiesForNullPropagation(Expression expression) + public bool ExpressionQualifiesForNullPropagation(Expression? expression) { return expression is MemberExpression || @@ -310,7 +309,7 @@ public Expression GenerateDefaultExpression(Type type) #endif } - private Expression GetMemberExpression(Expression expression) + private Expression? GetMemberExpression(Expression expression) { if (ExpressionQualifiesForNullPropagation(expression)) { @@ -335,7 +334,7 @@ private Expression GetMemberExpression(Expression expression) private List CollectExpressions(bool addSelf, Expression sourceExpression) { - Expression expression = GetMemberExpression(sourceExpression); + Expression? expression = GetMemberExpression(sourceExpression); var list = new List(); @@ -347,6 +346,7 @@ private List CollectExpressions(bool addSelf, Expression sourceExpre list.Add(sourceExpression); break; + // ReSharper disable once RedundantEmptySwitchSection default: break; } @@ -379,14 +379,14 @@ private List CollectExpressions(bool addSelf, Expression sourceExpre if (expressionRecognized && ExpressionQualifiesForNullPropagation(expression)) { - list.Add(expression); + list.Add(expression!); } } while (expressionRecognized); return list; } - private static Expression GetMethodCallExpression(MethodCallExpression methodCallExpression) + private static Expression? GetMethodCallExpression(MethodCallExpression methodCallExpression) { if (methodCallExpression.Object != null) { @@ -398,9 +398,9 @@ private static Expression GetMethodCallExpression(MethodCallExpression methodCal return methodCallExpression.Arguments.FirstOrDefault(); } - private static Expression GetUnaryExpression(UnaryExpression unaryExpression) + private static Expression? GetUnaryExpression(UnaryExpression? unaryExpression) { - return unaryExpression.Operand; + return unaryExpression?.Operand; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 204d9638..0972d6aa 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -32,11 +32,11 @@ public class ExpressionParser private readonly ITypeFinder _typeFinder; private readonly ITypeConverterFactory _typeConverterFactory; private readonly Dictionary _internals; - private readonly Dictionary _symbols; + private readonly Dictionary _symbols; - private IDictionary _externals; - private ParameterExpression _it; - private ParameterExpression _parent; + private IDictionary? _externals; + private ParameterExpression? _it; + private ParameterExpression? _parent; private ParameterExpression? _root; private Type? _resultType; private bool _createParameterCtor; @@ -62,11 +62,11 @@ public class ExpressionParser /// The expression. /// The values. /// The parsing configuration. - public ExpressionParser(ParameterExpression[]? parameters, string expression, object[]? values, ParsingConfig? parsingConfig) + public ExpressionParser(ParameterExpression[]? parameters, string expression, object?[]? values, ParsingConfig? parsingConfig) { Check.NotEmpty(expression, nameof(expression)); - _symbols = new Dictionary(parsingConfig != null && parsingConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); + _symbols = new Dictionary(parsingConfig != null && parsingConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); _internals = new Dictionary(); if (parameters != null) @@ -110,12 +110,12 @@ void ProcessParameters(ParameterExpression[] parameters) } } - void ProcessValues(object[] values) + void ProcessValues(object?[] values) { for (int i = 0; i < values.Length; i++) { - object value = values[i]; - IDictionary externals; + object? value = values[i]; + IDictionary? externals; if (i == values.Length - 1 && (externals = value as IDictionary) != null) { @@ -128,7 +128,7 @@ void ProcessValues(object[] values) } } - private void AddSymbol(string name, object value) + private void AddSymbol(string name, object? value) { if (_symbols.ContainsKey(name)) { @@ -150,7 +150,7 @@ public Expression Parse(Type? resultType, bool createParameterCtor = true) _createParameterCtor = createParameterCtor; int exprPos = _textParser.CurrentToken.Pos; - Expression expr = ParseConditionalOperator(); + Expression? expr = ParseConditionalOperator(); if (resultType != null) { @@ -242,7 +242,7 @@ Expression ParseNullCoalescingOperator() Expression ParseLambdaOperator() { Expression expr = ParseOrOperator(); - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == expr.Type) + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == expr.Type) { _textParser.NextToken(); if (_textParser.CurrentToken.Id == TokenId.Identifier || _textParser.CurrentToken.Id == TokenId.OpenParen) @@ -314,9 +314,9 @@ Expression ParseIn() Expression right = ParseUnary(); // if the identifier is an Enum, try to convert the right-side also to an Enum. - if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression) + if (left.Type.GetTypeInfo().IsEnum && right is ConstantExpression constantExpression) { - right = ParseEnumToConstantExpression(op.Pos, left.Type, right as ConstantExpression); + right = ParseEnumToConstantExpression(op.Pos, left.Type, constantExpression); } // else, check for direct type match @@ -355,7 +355,7 @@ Expression ParseIn() var args = new[] { left }; Expression? nullExpressionReference = null; - if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out MethodBase containsSignature) != 1) + if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1) { throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray())); } @@ -364,7 +364,7 @@ Expression ParseIn() args = new[] { right, left }; - accumulate = Expression.Call(typeof(Enumerable), containsSignature.Name, typeArgs, args); + accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args); } else { @@ -398,8 +398,7 @@ Expression ParseLogicalAndOrOperator() switch (op.Id) { case TokenId.Ampersand: - int parseValue; - if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out parseValue) && TypeHelper.IsNumericType(right.Type)) + if (left.Type == typeof(string) && left.NodeType == ExpressionType.Constant && int.TryParse((string)((ConstantExpression)left).Value, out var parseValue) && TypeHelper.IsNumericType(right.Type)) { left = Expression.Constant(parseValue); } @@ -469,7 +468,7 @@ Expression ParseComparisonOperator() { if (left.Type != right.Type) { - Expression e; + Expression? e; if ((e = _parsingConfig.ExpressionPromoter.Promote(right, left.Type, true, false)) != null) { right = e; @@ -841,12 +840,11 @@ Expression ParseIdentifier() { _textParser.ValidateToken(TokenId.Identifier); - if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object value) && + if (_keywordsHelper.TryGetValue(_textParser.CurrentToken.Text, out object? value) && // Prioritize property or field over the type !(value is Type && _it != null && FindPropertyOrField(_it.Type, _textParser.CurrentToken.Text, false) != null)) { - Type typeValue = value as Type; - if (typeValue != null) + if (value is Type typeValue) { return ParseTypeAccess(typeValue); } @@ -1029,7 +1027,7 @@ Expression ParseFunctionIs() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1059,7 +1057,7 @@ Expression ParseFunctionAs() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1089,7 +1087,7 @@ Expression ParseFunctionCast() if (args.Length == 1) { typeArgument = args[0]; - it = _it; + it = _it!; } else { @@ -1179,8 +1177,8 @@ Expression GenerateConditional(Expression test, Expression expressionIfTrue, Exp return Expression.Condition(test, expressionIfTrue, expressionIfFalse); } - Expression expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; - Expression expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; + var expr1As2 = !Constants.IsNull(expressionIfFalse) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfTrue, expressionIfFalse.Type, true, false) : null; + var expr2As1 = !Constants.IsNull(expressionIfTrue) ? _parsingConfig.ExpressionPromoter.Promote(expressionIfFalse, expressionIfTrue.Type, true, false) : null; if (expr1As2 != null && expr2As1 == null) { expressionIfTrue = expr1As2; @@ -1217,7 +1215,7 @@ Expression ParseNew() throw ParseError(Res.OpenParenOrIdentifierExpected); } - Type newType = null; + Type? newType = null; if (_textParser.CurrentToken.Id == TokenId.Identifier) { var newTypeName = _textParser.CurrentToken.Text; @@ -1323,7 +1321,7 @@ Expression ParseNew() return CreateNewExpression(properties, expressions, newType); } - private Expression CreateArrayInitializerExpression(List expressions, Type newType) + private Expression CreateArrayInitializerExpression(List expressions, Type? newType) { if (expressions.Count == 0) { @@ -1338,10 +1336,10 @@ private Expression CreateArrayInitializerExpression(List expressions return Expression.NewArrayInit(expressions.All(expression => expression.Type == expressions[0].Type) ? expressions[0].Type : typeof(object), expressions); } - private Expression CreateNewExpression(List properties, List expressions, Type newType) + private Expression CreateNewExpression(List properties, List expressions, Type? newType) { // http://solutionizing.net/category/linq/ - Type type = newType ?? _resultType; + Type? type = newType ?? _resultType; if (type == null) { @@ -1388,7 +1386,7 @@ private Expression CreateNewExpression(List properties, List constructorParameters .Any(cp => cp.Name == p.Name && (cp.ParameterType == p.Type || p.Type == Nullable.GetUnderlyingType(cp.ParameterType)))); - var expressionsPromoted = new List(); + var expressionsPromoted = new List(); // Loop all expressions and promote if needed for (int i = 0; i < constructorParameters.Length; i++) @@ -1432,7 +1430,7 @@ private Expression CreateNewExpression(List properties, List properties, List properties, List !c.GetParameters().Any(p => p.ParameterType.GetTypeInfo().IsPointer)) .ToArray(); - switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out MethodBase method)) + switch (_methodFinder.FindBestMethodBasedOnArguments(constructorsWithOutPointerArguments, ref args, out var method)) { case 0: if (args.Length == 1 && TryGenerateConversion(args[0], type, out generatedExpression)) { - return generatedExpression; + return generatedExpression!; } throw ParseError(errorPos, Res.NoMatchingConstructor, TypeHelper.GetTypeName(type)); case 1: - return Expression.New((ConstructorInfo)method, args); + return Expression.New((ConstructorInfo)method!, args); default: throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, TypeHelper.GetTypeName(type)); @@ -1545,7 +1546,7 @@ Expression ParseTypeAccess(Type type) return ParseMemberAccess(type, null); } - private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression expression) + private bool TryGenerateConversion(Expression sourceExpression, Type type, out Expression? expression) { Type exprType = sourceExpression.Type; if (exprType == type) @@ -1601,7 +1602,7 @@ private bool TryGenerateConversion(Expression sourceExpression, Type type, out E return false; } - Expression ParseMemberAccess(Type type, Expression expression) + Expression ParseMemberAccess(Type? type, Expression? expression) { if (expression != null) { @@ -1616,7 +1617,7 @@ Expression ParseMemberAccess(Type type, Expression expression) { if (expression != null && type != typeof(string)) { - Type enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); + var enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type); if (enumerableType != null) { Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0]; @@ -1625,16 +1626,16 @@ Expression ParseMemberAccess(Type type, Expression expression) } Expression[] args = ParseArgumentList(); - switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out MethodBase mb)) + switch (_methodFinder.FindMethod(type, id, expression == null, ref expression, ref args, out var mb)) { case 0: - throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type)); + throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type!)); case 1: - MethodInfo method = (MethodInfo)mb; - if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) + MethodInfo method = (MethodInfo)mb!; + if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !(method.IsPublic && PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.ReturnType))) { - throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType)); + throw ParseError(errorPos, Res.MethodsAreInaccessible, TypeHelper.GetTypeName(method.DeclaringType!)); } if (method.IsGenericMethod) @@ -1644,10 +1645,8 @@ Expression ParseMemberAccess(Type type, Expression expression) var constructedMethod = method.MakeGenericMethod(typeArguments.ToArray()); return Expression.Call(expression, constructedMethod, args); } - else - { - return Expression.Call(expression, method, args); - } + + return Expression.Call(expression, method, args); default: throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, TypeHelper.GetTypeName(type)); @@ -1666,7 +1665,7 @@ Expression ParseMemberAccess(Type type, Expression expression) return Expression.MakeIndex(expression, typeof(DynamicClass).GetProperty("Item"), new[] { Expression.Constant(id) }); } #endif - MemberInfo member = FindPropertyOrField(type, id, expression == null); + MemberInfo? member = FindPropertyOrField(type!, id, expression == null); if (member is PropertyInfo property) { return Expression.Property(expression, property); @@ -1679,7 +1678,7 @@ Expression ParseMemberAccess(Type type, Expression expression) if (!_parsingConfig.DisableMemberAccessToIndexAccessorFallback && expression != null) { - MethodInfo indexerMethod = expression.Type.GetMethod("get_Item", new[] { typeof(string) }); + var indexerMethod = expression.Type.GetMethod("get_Item", new[] { typeof(string) }); if (indexerMethod != null) { return Expression.Call(expression, indexerMethod, Expression.Constant(id)); @@ -1694,7 +1693,7 @@ Expression ParseMemberAccess(Type type, Expression expression) } #endif // Parse as Lambda - if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == type) + if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == type) { return ParseAsLambda(id); } @@ -1774,14 +1773,14 @@ private Expression ParseAsEnum(string id) return Expression.Constant(enumValue); } - Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type type) + Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type) { bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null; bool isDictionary = TypeHelper.IsDictionary(type); var oldParent = _parent; - ParameterExpression outerIt = _it; + ParameterExpression? outerIt = _it; ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames); _parent = _it; @@ -2094,16 +2093,14 @@ static Exception IncompatibleOperandsError(string opName, Expression left, Expre return ParseError(errorPos, Res.IncompatibleOperands, opName, TypeHelper.GetTypeName(left.Type), TypeHelper.GetTypeName(right.Type)); } - private MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) + private MemberInfo? FindPropertyOrField(Type type, string memberName, bool staticAccess) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { - MemberInfo[] members = null; - var findMembersType = _parsingConfig?.IsCaseSensitive == true ? Type.FilterName : Type.FilterNameIgnoreCase; - members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, flags, findMembersType, memberName); + var members = t.FindMembers(MemberTypes.Property | MemberTypes.Field, flags, findMembersType, memberName); if (members.Length != 0) { @@ -2116,7 +2113,7 @@ private MemberInfo FindPropertyOrField(Type type, string memberName, bool static foreach (Type t in TypeHelper.GetSelfAndBaseTypes(type)) { // Try to find a property with the specified memberName - MemberInfo member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); + MemberInfo? member = t.GetTypeInfo().DeclaredProperties.FirstOrDefault(x => (!staticAccess || x.GetAccessors(true)[0].IsStatic) && ((x.Name == memberName) || (!isCaseSensitive && x.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)))); if (member != null) { return member; diff --git a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs index cabae88c..8fb14e71 100644 --- a/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/IExpressionHelper.cs @@ -26,7 +26,7 @@ internal interface IExpressionHelper void OptimizeForEqualityIfPossible(ref Expression left, ref Expression right); - Expression OptimizeStringForEqualityIfPossible(string text, Type type); + Expression? OptimizeStringForEqualityIfPossible(string text, Type type); bool TryGenerateAndAlsoNotNullExpression(Expression sourceExpression, bool addSelf, out Expression generatedExpression); diff --git a/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs b/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs index 0de66306..ece62c52 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ITypeFinder.cs @@ -1,10 +1,9 @@ using System.Linq.Expressions; -using JetBrains.Annotations; namespace System.Linq.Dynamic.Core.Parser { interface ITypeFinder { - Type FindTypeByName([NotNull] string name, [CanBeNull] ParameterExpression[] expressions, bool forceUseCustomTypeProvider); + Type? FindTypeByName(string name, ParameterExpression?[]? expressions, bool forceUseCustomTypeProvider); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs index 4bf115ba..d42377a8 100644 --- a/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/PredefinedTypesHelper.cs @@ -74,7 +74,7 @@ private static void TryAdd(string typeName, int x) { try { - Type efType = Type.GetType(typeName); + Type? efType = Type.GetType(typeName); if (efType != null) { PredefinedTypes.Add(efType, x); diff --git a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs index d1c7339c..40b41848 100644 --- a/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/SupportedMethods/MethodFinder.cs @@ -25,7 +25,7 @@ public bool ContainsMethod(Type type, string methodName, bool staticAccess, Expr return FindMethod(type, methodName, staticAccess, ref instance, ref args, out _) == 1; } - public int FindMethod(Type type, string methodName, bool staticAccess, ref Expression? instance, ref Expression[] args, out MethodBase? method) + public int FindMethod(Type? type, string methodName, bool staticAccess, ref Expression? instance, ref Expression[] args, out MethodBase? method) { #if !(NETFX_CORE || WINDOWS_APP || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); @@ -68,6 +68,8 @@ public int FindMethod(Type type, string methodName, bool staticAccess, ref Expre argsList.Insert(0, instance); var extensionMethodArgs = argsList.ToArray(); + + // ReSharper disable once RedundantEnumerableCastCall int count = FindBestMethodBasedOnArguments(methods.Cast(), ref extensionMethodArgs, out method); if (count != 0) { @@ -297,9 +299,9 @@ CompareConversionType CompareConversions(Type source, Type first, Type second) return CompareConversionType.Both; } - IEnumerable SelfAndBaseTypes(Type type) + IEnumerable SelfAndBaseTypes(Type? type) { - if (type.GetTypeInfo().IsInterface) + if (type?.GetTypeInfo().IsInterface == true) { var types = new List(); AddInterface(types, type); @@ -308,7 +310,7 @@ IEnumerable SelfAndBaseTypes(Type type) return SelfAndBaseClasses(type); } - IEnumerable SelfAndBaseClasses(Type type) + IEnumerable SelfAndBaseClasses(Type? type) { while (type != null) { diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs index 08e27cd6..5b827fee 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Linq.Dynamic.Core.Validation; +using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; namespace System.Linq.Dynamic.Core.Parser @@ -9,7 +8,7 @@ internal class TypeFinder : ITypeFinder private readonly IKeywordsHelper _keywordsHelper; private readonly ParsingConfig _parsingConfig; - public TypeFinder([NotNull] ParsingConfig parsingConfig, [NotNull] IKeywordsHelper keywordsHelper) + public TypeFinder(ParsingConfig parsingConfig, IKeywordsHelper keywordsHelper) { Check.NotNull(parsingConfig, nameof(parsingConfig)); Check.NotNull(keywordsHelper, nameof(keywordsHelper)); @@ -18,30 +17,30 @@ public TypeFinder([NotNull] ParsingConfig parsingConfig, [NotNull] IKeywordsHelp _parsingConfig = parsingConfig; } - public Type FindTypeByName(string name, ParameterExpression[] expressions, bool forceUseCustomTypeProvider) + public Type? FindTypeByName(string name, ParameterExpression?[]? expressions, bool forceUseCustomTypeProvider) { Check.NotEmpty(name, nameof(name)); - _keywordsHelper.TryGetValue(name, out object type); + _keywordsHelper.TryGetValue(name, out var type); - if (type is Type result) + if (type is Type sameType) { - return result; + return sameType; } - if (expressions != null && TryResolveTypeUsingExpressions(name, expressions, out result)) + if (expressions != null && TryResolveTypeUsingExpressions(name, expressions, out var resolvedType)) { - return result; + return resolvedType; } return ResolveTypeByUsingCustomTypeProvider(name, forceUseCustomTypeProvider); } - private Type ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCustomTypeProvider) + private Type? ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCustomTypeProvider) { if ((forceUseCustomTypeProvider || _parsingConfig.AllowNewToEvaluateAnyType) && _parsingConfig.CustomTypeProvider != null) { - Type resolvedType = _parsingConfig.CustomTypeProvider.ResolveType(name); + var resolvedType = _parsingConfig.CustomTypeProvider.ResolveType(name); if (resolvedType != null) { return resolvedType; @@ -57,11 +56,11 @@ private Type ResolveTypeByUsingCustomTypeProvider(string name, bool forceUseCust return null; } - private bool TryResolveTypeUsingExpressions(string name, ParameterExpression[] expressions, out Type result) + private bool TryResolveTypeUsingExpressions(string name, ParameterExpression?[] expressions, out Type? result) { foreach (var expression in expressions.Where(e => e != null)) { - if (name == expression.Type.Name) + if (name == expression!.Type.Name) { result = expression.Type; return true; @@ -89,4 +88,4 @@ private bool TryResolveTypeUsingExpressions(string name, ParameterExpression[] e return false; } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index a16465c3..cd30ae31 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -6,7 +6,7 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class TypeHelper { - public static Type? FindGenericType(Type generic, Type type) + public static Type? FindGenericType(Type generic, Type? type) { while (type != null && type != typeof(object)) { @@ -443,9 +443,9 @@ private static void AddInterface(List types, Type type) } } - public static object? ParseEnum(string value, Type type) + public static object? ParseEnum(string value, Type? type) { - if (type.GetTypeInfo().IsEnum && Enum.IsDefined(type, value)) + if (type is { } && type.GetTypeInfo().IsEnum && Enum.IsDefined(type, value)) { return Enum.Parse(type, value, true); } @@ -453,7 +453,7 @@ private static void AddInterface(List types, Type type) return null; } - public static bool IsDictionary(Type type) + public static bool IsDictionary(Type? type) { return FindGenericType(typeof(IDictionary<,>), type) != null || @@ -465,4 +465,4 @@ public static bool IsDictionary(Type type) #endif } } -} +} \ No newline at end of file From 1f7401054563699feba5b29f953e7adc8ad87696 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 21 Oct 2022 14:25:04 +0200 Subject: [PATCH 5/9] . --- .../DynamicExpressionParser.cs | 72 ++++++++----------- src/System.Linq.Dynamic.Core/ParsingConfig.cs | 23 +++--- .../Tokenizer/TextParser.cs | 13 ++-- 3 files changed, 50 insertions(+), 58 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index df051747..06717c8f 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -21,7 +21,7 @@ public static class DynamicExpressionParser /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -41,7 +41,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -60,7 +60,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, typeof(TResult), expression, values); } @@ -76,7 +76,7 @@ public static Expression> ParseLambda(ParsingConfig? pars /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); return (Expression>)ParseLambda(delegateType, parsingConfig, createParameterCtor, typeof(TResult), expression, values); @@ -93,7 +93,7 @@ public static Expression> ParseLambda(Type delegateType, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(null, parsingConfig, createParameterCtor, parameters, resultType, expression, values); } @@ -110,7 +110,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { Check.NotNull(parameters, nameof(parameters)); Check.HasNoNulls(parameters, nameof(parameters)); @@ -121,30 +121,20 @@ public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? pa var parsedExpression = parser.Parse(resultType, createParameterCtor); LambdaExpression lambdaExpression; - if (parsingConfig != null && parsingConfig.RenameParameterExpression && parameters.Length == 1) + if (parsingConfig is { RenameParameterExpression: true } && parameters.Length == 1) { var renamer = new ParameterExpressionRenamer(parser.LastLambdaItName); parsedExpression = renamer.Rename(parsedExpression, out ParameterExpression newParameterExpression); - if (delegateType == null) - { - lambdaExpression = Expression.Lambda(parsedExpression, new[] { newParameterExpression }); - } - else - { - lambdaExpression = Expression.Lambda(delegateType, parsedExpression, new[] { newParameterExpression }); - } + lambdaExpression = delegateType == null ? + Expression.Lambda(parsedExpression, newParameterExpression) : + Expression.Lambda(delegateType, parsedExpression, newParameterExpression); } else { - if (delegateType == null) - { - lambdaExpression = Expression.Lambda(parsedExpression, parameters); - } - else - { - lambdaExpression = Expression.Lambda(delegateType, parsedExpression, parameters); - } + lambdaExpression = delegateType == null ? + Expression.Lambda(parsedExpression, parameters) : + Expression.Lambda(delegateType, parsedExpression, parameters); } return lambdaExpression; @@ -161,7 +151,7 @@ public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? pa /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[]values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[] values) { return (Expression>)ParseLambda(parsingConfig, createParameterCtor, parameters, typeof(TResult), expression, values); } @@ -178,7 +168,7 @@ public static Expression> ParseLambda(ParsingConfig? pars /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[]values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -195,7 +185,7 @@ public static Expression> ParseLambda(Type delegateType, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -214,7 +204,7 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, Type itType /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) + public static Expression> ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -233,7 +223,7 @@ public static Expression> ParseLambda(ParsingConfig /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[]values) + public static Expression> ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotEmpty(expression, nameof(expression)); @@ -250,7 +240,7 @@ public static Expression> ParseLambda(Type delegate /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[] values) { return ParseLambda(parsingConfig, true, resultType, expression, values); } @@ -265,7 +255,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type? r /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type? resultType, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -280,7 +270,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type? resultType, string expression, params object?[] values) { Check.NotEmpty(expression, nameof(expression)); @@ -305,7 +295,7 @@ public static LambdaExpression ParseLambda(Type? resultType, string expression, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(itType, nameof(itType)); @@ -322,7 +312,7 @@ public static LambdaExpression ParseLambda(Type itType, Type? resultType, string /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(itType, nameof(itType)); @@ -340,7 +330,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Type it /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); @@ -359,7 +349,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); @@ -379,7 +369,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); Check.NotNull(itType, nameof(itType)); @@ -397,7 +387,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(null, true, parameters, resultType, expression, values); } @@ -412,7 +402,7 @@ public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Typ /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -429,7 +419,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParameterExpressio /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(parsingConfig, true, parameters, resultType, expression, values); } @@ -445,7 +435,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, Paramet /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? parsingConfig, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { Check.NotNull(delegateType, nameof(delegateType)); @@ -462,7 +452,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]values) + public static LambdaExpression ParseLambda(bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) { return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values); } diff --git a/src/System.Linq.Dynamic.Core/ParsingConfig.cs b/src/System.Linq.Dynamic.Core/ParsingConfig.cs index 856c67b4..da6c2a03 100644 --- a/src/System.Linq.Dynamic.Core/ParsingConfig.cs +++ b/src/System.Linq.Dynamic.Core/ParsingConfig.cs @@ -35,11 +35,11 @@ public class ParsingConfig RenameEmptyParameterExpressionNames = true }; - private IDynamicLinkCustomTypeProvider _customTypeProvider; + private IDynamicLinkCustomTypeProvider? _customTypeProvider; - private IExpressionPromoter _expressionPromoter; + private IExpressionPromoter? _expressionPromoter; - private IQueryableAnalyzer _queryableAnalyzer; + private IQueryableAnalyzer? _queryableAnalyzer; /// /// Gets or sets the . @@ -50,7 +50,7 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider { #if !( WINDOWS_APP || UAP10_0 || NETSTANDARD) // only use DefaultDynamicLinqCustomTypeProvider for full .NET Framework and NET Core App 2.x - return _customTypeProvider ?? (_customTypeProvider = new DefaultDynamicLinqCustomTypeProvider()); + return _customTypeProvider ??= new DefaultDynamicLinqCustomTypeProvider(); #else return _customTypeProvider; #endif @@ -58,6 +58,7 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_customTypeProvider != value) { _customTypeProvider = value; @@ -70,10 +71,11 @@ public IDynamicLinkCustomTypeProvider CustomTypeProvider /// public IExpressionPromoter ExpressionPromoter { - get => _expressionPromoter ?? (_expressionPromoter = new ExpressionPromoter(this)); + get => _expressionPromoter ??= new ExpressionPromoter(this); set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_expressionPromoter != value) { _expressionPromoter = value; @@ -88,11 +90,12 @@ public IQueryableAnalyzer QueryableAnalyzer { get { - return _queryableAnalyzer ?? (_queryableAnalyzer = new DefaultQueryableAnalyzer()); + return _queryableAnalyzer ??= new DefaultQueryableAnalyzer(); } set { + // ReSharper disable once RedundantCheckBeforeAssignment if (_queryableAnalyzer != value) { _queryableAnalyzer = value; @@ -116,7 +119,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool EvaluateGroupByAtDatabase { get; set; } = false; + public bool EvaluateGroupByAtDatabase { get; set; } /// /// Use Parameterized Names in generated dynamic SQL query. @@ -145,7 +148,7 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is false. /// - public bool RenameEmptyParameterExpressionNames { get; set; } = false; + public bool RenameEmptyParameterExpressionNames { get; set; } /// /// By default when a member is not found in a type and the type has a string based index accessor it will be parsed as an index accessor. Use @@ -185,12 +188,12 @@ public IQueryableAnalyzer QueryableAnalyzer /// /// Default value is CultureInfo.InvariantCulture /// - public CultureInfo NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; + public CultureInfo? NumberParseCulture { get; set; } = CultureInfo.InvariantCulture; /// /// Additional TypeConverters /// - public IDictionary TypeConverters { get; set; } + public IDictionary? TypeConverters { get; set; } /// /// When using the NullPropagating function np(...), use a "default value" for non-nullable value types instead of "null value". diff --git a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs index fa42300f..83839d82 100644 --- a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs +++ b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs @@ -13,7 +13,7 @@ public class TextParser private static readonly char[] EscapeCharacters = { '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v' }; // These aliases are supposed to simply the where clause and make it more human readable - private static readonly Dictionary PredefinedOperatorAliases = new Dictionary(StringComparer.OrdinalIgnoreCase) + private static readonly Dictionary PredefinedOperatorAliases = new(StringComparer.OrdinalIgnoreCase) { { "eq", TokenId.Equal }, { "equal", TokenId.Equal }, @@ -36,7 +36,6 @@ public class TextParser { "mod", TokenId.Percent } }; - private readonly ParsingConfig _config; private readonly char _numberDecimalSeparator; private readonly string _text; private readonly int _textLen; @@ -56,7 +55,6 @@ public class TextParser /// public TextParser(ParsingConfig config, string text) { - _config = config; _numberDecimalSeparator = config.NumberParseCulture?.NumberFormat.NumberDecimalSeparator[0] ?? DefaultNumberDecimalSeparator; _text = text; @@ -100,6 +98,7 @@ public void NextToken() NextChar(); } + // ReSharper disable once RedundantAssignment TokenId tokenId = TokenId.Unknown; int tokenPos = _textPos; @@ -449,7 +448,7 @@ public void NextToken() /// /// The tokenId to check. /// The (optional) error message. - public void ValidateToken(TokenId tokenId, string errorMessage = null) + public void ValidateToken(TokenId tokenId, string? errorMessage = null) { if (CurrentToken.Id != tokenId) { @@ -514,7 +513,7 @@ private static bool IsHexChar(char c) if (c <= '\x007f') { c |= (char)0x20; - return c >= 'a' && c <= 'f'; + return c is >= 'a' and <= 'f'; } return false; @@ -522,7 +521,7 @@ private static bool IsHexChar(char c) private static bool IsZeroOrOne(char c) { - return c == '0' || c == '1'; + return c is '0' or '1'; } } -} +} \ No newline at end of file From f4a922afb1e08481e7e2f57927e4a2f26a34a3fb Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 21 Oct 2022 18:43:32 +0200 Subject: [PATCH 6/9] x --- .../Parser/ExpressionParser.cs | 173 +++++++++--------- .../Parser/TypeHelper.cs | 7 +- .../TypeConverters/TypeConverterFactory.cs | 9 +- 3 files changed, 98 insertions(+), 91 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 0972d6aa..ace1822f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -18,10 +18,10 @@ namespace System.Linq.Dynamic.Core.Parser /// public class ExpressionParser { - static readonly string methodOrderBy = nameof(Queryable.OrderBy); - static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); - static readonly string methodThenBy = nameof(Queryable.ThenBy); - static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); + private static readonly string methodOrderBy = nameof(Queryable.OrderBy); + private static readonly string methodOrderByDescending = nameof(Queryable.OrderByDescending); + private static readonly string methodThenBy = nameof(Queryable.ThenBy); + private static readonly string methodThenByDescending = nameof(Queryable.ThenByDescending); private readonly ParsingConfig _parsingConfig; private readonly MethodFinder _methodFinder; @@ -31,7 +31,7 @@ public class ExpressionParser private readonly IExpressionHelper _expressionHelper; private readonly ITypeFinder _typeFinder; private readonly ITypeConverterFactory _typeConverterFactory; - private readonly Dictionary _internals; + private readonly Dictionary _internals = new(); private readonly Dictionary _symbols; private IDictionary? _externals; @@ -66,8 +66,16 @@ public ExpressionParser(ParameterExpression[]? parameters, string expression, ob { Check.NotEmpty(expression, nameof(expression)); - _symbols = new Dictionary(parsingConfig != null && parsingConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); - _internals = new Dictionary(); + _symbols = new Dictionary(parsingConfig is { IsCaseSensitive: true } ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); + _parsingConfig = parsingConfig ?? ParsingConfig.Default; + + _keywordsHelper = new KeywordsHelper(_parsingConfig); + _textParser = new TextParser(_parsingConfig, expression); + _numberParser = new NumberParser(parsingConfig); + _methodFinder = new MethodFinder(_parsingConfig); + _expressionHelper = new ExpressionHelper(_parsingConfig); + _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); + _typeConverterFactory = new TypeConverterFactory(_parsingConfig); if (parameters != null) { @@ -78,19 +86,9 @@ public ExpressionParser(ParameterExpression[]? parameters, string expression, ob { ProcessValues(values); } - - _parsingConfig = parsingConfig ?? ParsingConfig.Default; - - _keywordsHelper = new KeywordsHelper(_parsingConfig); - _textParser = new TextParser(_parsingConfig, expression); - _numberParser = new NumberParser(parsingConfig); - _methodFinder = new MethodFinder(_parsingConfig); - _expressionHelper = new ExpressionHelper(_parsingConfig); - _typeFinder = new TypeFinder(_parsingConfig, _keywordsHelper); - _typeConverterFactory = new TypeConverterFactory(_parsingConfig); } - void ProcessParameters(ParameterExpression[] parameters) + private void ProcessParameters(ParameterExpression[] parameters) { foreach (ParameterExpression pe in parameters.Where(p => !string.IsNullOrEmpty(p.Name))) { @@ -110,7 +108,7 @@ void ProcessParameters(ParameterExpression[] parameters) } } - void ProcessValues(object?[] values) + private void ProcessValues(object?[] values) { for (int i = 0; i < values.Length; i++) { @@ -209,7 +207,7 @@ internal IList ParseOrdering(bool forceThenBy = false) #pragma warning restore 0219 // ?: operator - Expression ParseConditionalOperator() + private Expression ParseConditionalOperator() { int errorPos = _textParser.CurrentToken.Pos; Expression expr = ParseNullCoalescingOperator(); @@ -226,7 +224,7 @@ Expression ParseConditionalOperator() } // ?? (null-coalescing) operator - Expression ParseNullCoalescingOperator() + private Expression ParseNullCoalescingOperator() { Expression expr = ParseLambdaOperator(); if (_textParser.CurrentToken.Id == TokenId.NullCoalescing) @@ -239,7 +237,7 @@ Expression ParseNullCoalescingOperator() } // => operator - Added Support for projection operator - Expression ParseLambdaOperator() + private Expression ParseLambdaOperator() { Expression expr = ParseOrOperator(); if (_textParser.CurrentToken.Id == TokenId.Lambda && _it?.Type == expr.Type) @@ -259,7 +257,7 @@ Expression ParseLambdaOperator() // - || // - Or // - OrElse - Expression ParseOrOperator() + private Expression ParseOrOperator() { Expression left = ParseAndOperator(); while (_textParser.CurrentToken.Id == TokenId.DoubleBar) @@ -277,7 +275,7 @@ Expression ParseOrOperator() // - && // - And // - AndAlso - Expression ParseAndOperator() + private Expression ParseAndOperator() { Expression left = ParseIn(); while (_textParser.CurrentToken.Id == TokenId.DoubleAmpersand) @@ -294,7 +292,7 @@ Expression ParseAndOperator() // in operator for literals - example: "x in (1,2,3,4)" // in operator to mimic contains - example: "x in @0", compare to @0.Contains(x) // Adapted from ticket submitted by github user mlewis9548 - Expression ParseIn() + private Expression ParseIn() { Expression left = ParseLogicalAndOrOperator(); Expression accumulate = left; @@ -376,7 +374,7 @@ Expression ParseIn() } // &, | bitwise operators - Expression ParseLogicalAndOrOperator() + private Expression ParseLogicalAndOrOperator() { Expression left = ParseComparisonOperator(); while (_textParser.CurrentToken.Id == TokenId.Ampersand || _textParser.CurrentToken.Id == TokenId.Bar) @@ -430,7 +428,7 @@ Expression ParseLogicalAndOrOperator() } // =, ==, !=, <>, >, >=, <, <= operators - Expression ParseComparisonOperator() + private Expression ParseComparisonOperator() { Expression left = ParseShiftOperator(); while (_textParser.CurrentToken.Id == TokenId.Equal || _textParser.CurrentToken.Id == TokenId.DoubleEqual || @@ -620,7 +618,7 @@ private object ParseConstantExpressionToEnum(int pos, Type leftType, ConstantExp } // <<, >> operators - Expression ParseShiftOperator() + private Expression ParseShiftOperator() { Expression left = ParseAdditive(); while (_textParser.CurrentToken.Id == TokenId.DoubleLessThan || _textParser.CurrentToken.Id == TokenId.DoubleGreaterThan) @@ -644,7 +642,7 @@ Expression ParseShiftOperator() } // +, - operators - Expression ParseAdditive() + private Expression ParseAdditive() { Expression left = ParseMultiplicative(); while (_textParser.CurrentToken.Id == TokenId.Plus || _textParser.CurrentToken.Id == TokenId.Minus) @@ -675,7 +673,7 @@ Expression ParseAdditive() } // *, /, %, mod operators - Expression ParseMultiplicative() + private Expression ParseMultiplicative() { Expression left = ParseUnary(); while (_textParser.CurrentToken.Id == TokenId.Asterisk || _textParser.CurrentToken.Id == TokenId.Slash || @@ -703,7 +701,7 @@ Expression ParseMultiplicative() } // -, !, not unary operators - Expression ParseUnary() + private Expression ParseUnary() { if (_textParser.CurrentToken.Id == TokenId.Minus || _textParser.CurrentToken.Id == TokenId.Exclamation || TokenIdentifierIs("not")) { @@ -734,7 +732,7 @@ Expression ParseUnary() return ParsePrimary(); } - Expression ParsePrimary() + private Expression ParsePrimary() { Expression expr = ParsePrimaryStart(); _expressionHelper.WrapConstantExpression(ref expr); @@ -762,7 +760,7 @@ Expression ParsePrimary() return expr; } - Expression ParsePrimaryStart() + private Expression ParsePrimaryStart() { switch (_textParser.CurrentToken.Id) { @@ -781,7 +779,7 @@ Expression ParsePrimaryStart() } } - Expression ParseStringLiteral() + private Expression ParseStringLiteral() { _textParser.ValidateToken(TokenId.StringLiteral); @@ -802,7 +800,7 @@ Expression ParseStringLiteral() return ConstantExpressionHelper.CreateLiteral(result, result); } - Expression ParseIntegerLiteral() + private Expression ParseIntegerLiteral() { _textParser.ValidateToken(TokenId.IntegerLiteral); @@ -815,7 +813,7 @@ Expression ParseIntegerLiteral() return constantExpression; } - Expression ParseRealLiteral() + private Expression ParseRealLiteral() { _textParser.ValidateToken(TokenId.RealLiteral); @@ -826,7 +824,7 @@ Expression ParseRealLiteral() return _numberParser.ParseRealLiteral(text, text[text.Length - 1], true); } - Expression ParseParenExpression() + private Expression ParseParenExpression() { _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); _textParser.NextToken(); @@ -836,7 +834,7 @@ Expression ParseParenExpression() return e; } - Expression ParseIdentifier() + private Expression ParseIdentifier() { _textParser.ValidateToken(TokenId.Identifier); @@ -920,7 +918,7 @@ Expression ParseIdentifier() throw ParseError(Res.UnknownIdentifier, _textParser.CurrentToken.Text); } - Expression ParseIt() + private Expression ParseIt() { if (_it == null) { @@ -930,7 +928,7 @@ Expression ParseIt() return _it; } - Expression ParseParent() + private Expression ParseParent() { if (_parent == null) { @@ -940,7 +938,7 @@ Expression ParseParent() return _parent; } - Expression ParseRoot() + private Expression ParseRoot() { if (_root == null) { @@ -951,7 +949,7 @@ Expression ParseRoot() } // isnull(a,b) function - Expression ParseFunctionIsNull() + private Expression ParseFunctionIsNull() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -965,7 +963,7 @@ Expression ParseFunctionIsNull() } // iif(test, ifTrue, ifFalse) function - Expression ParseFunctionIif() + private Expression ParseFunctionIif() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -980,7 +978,7 @@ Expression ParseFunctionIif() } // np(...) function - Expression ParseFunctionNullPropagation() + private Expression ParseFunctionNullPropagation() { int errorPos = _textParser.CurrentToken.Pos; _textParser.NextToken(); @@ -1009,7 +1007,7 @@ Expression ParseFunctionNullPropagation() } // Is(...) function - Expression ParseFunctionIs() + private Expression ParseFunctionIs() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1039,7 +1037,7 @@ Expression ParseFunctionIs() } // As(...) function - Expression ParseFunctionAs() + private Expression ParseFunctionAs() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1069,7 +1067,7 @@ Expression ParseFunctionAs() } // Cast(...) function - Expression ParseFunctionCast() + private Expression ParseFunctionCast() { int errorPos = _textParser.CurrentToken.Pos; string functionName = _textParser.CurrentToken.Text; @@ -1098,7 +1096,7 @@ Expression ParseFunctionCast() return Expression.ConvertChecked(it, ResolveTypeFromArgumentExpression(functionName, typeArgument, args.Length)); } - Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) + private Expression GenerateConditional(Expression test, Expression expressionIfTrue, Expression expressionIfFalse, bool nullPropagating, int errorPos) { if (test.Type != typeof(bool)) { @@ -1204,7 +1202,7 @@ Expression GenerateConditional(Expression test, Expression expressionIfTrue, Exp } // new (...) function - Expression ParseNew() + private Expression ParseNew() { _textParser.NextToken(); if (_textParser.CurrentToken.Id != TokenId.OpenParen && @@ -1268,7 +1266,7 @@ Expression ParseNew() Expression expr = ParseConditionalOperator(); if (!arrayInitializer) { - string propName; + string? propName; if (TokenIdentifierIs("as")) { _textParser.NextToken(); @@ -1277,7 +1275,7 @@ Expression ParseNew() } else { - if (!TryGetMemberName(expr, out propName)) + if (!TryGetMemberName(expr, out propName)) // TODO : investigate this { if (expr is MethodCallExpression methodCallExpression && methodCallExpression.Arguments.Count == 1 @@ -1294,7 +1292,10 @@ Expression ParseNew() } } - properties.Add(new DynamicProperty(propName, expr.Type)); + if (!string.IsNullOrEmpty(propName)) + { + properties.Add(new DynamicProperty(propName!, expr.Type)); + } } expressions.Add(expr); @@ -1460,7 +1461,7 @@ private Expression CreateNewExpression(List properties, List), type) != null; bool isDictionary = TypeHelper.IsDictionary(type); @@ -1802,7 +1806,7 @@ Expression ParseEnumerable(Expression instance, Type elementType, string methodN if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args)) { - var method = type.GetMethod(methodName); + var method = type!.GetMethod(methodName)!; return Expression.Call(instance, method, args); } @@ -1887,7 +1891,7 @@ private Type ResolveTypeFromArgumentExpression(string functionName, Expression a switch (constantExpression.Value) { case string typeName: - return ResolveTypeStringFromArgument(functionName, typeName); + return ResolveTypeStringFromArgument(typeName); case Type type: return type; @@ -1901,9 +1905,9 @@ private Type ResolveTypeFromArgumentExpression(string functionName, Expression a } } - private Type ResolveTypeStringFromArgument(string functionName, string typeName) + private Type ResolveTypeStringFromArgument(string typeName) { - Type resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); + var resultType = _typeFinder.FindTypeByName(typeName, new[] { _it, _parent, _root }, true); if (resultType == null) { throw ParseError(_textParser.CurrentToken.Pos, Res.TypeNotFound, typeName); @@ -1912,7 +1916,7 @@ private Type ResolveTypeStringFromArgument(string functionName, string typeName) return resultType; } - Expression[] ParseArgumentList() + private Expression[] ParseArgumentList() { _textParser.ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); _textParser.NextToken(); @@ -1922,7 +1926,7 @@ Expression[] ParseArgumentList() return args; } - Expression[] ParseArguments() + private Expression[] ParseArguments() { var argList = new List(); while (true) @@ -1944,7 +1948,7 @@ Expression[] ParseArguments() return argList.ToArray(); } - Expression ParseElementAccess(Expression expr) + private Expression ParseElementAccess(Expression expr) { int errorPos = _textParser.CurrentToken.Pos; _textParser.ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected); @@ -1960,14 +1964,14 @@ Expression ParseElementAccess(Expression expr) { throw ParseError(errorPos, Res.CannotIndexMultiDimArray); } - Expression index = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); - if (index == null) + var indexExpression = _parsingConfig.ExpressionPromoter.Promote(args[0], typeof(int), true, false); + if (indexExpression == null) { throw ParseError(errorPos, Res.InvalidIndex); } - return Expression.ArrayIndex(expr, index); + return Expression.ArrayIndex(expr, indexExpression); } switch (_methodFinder.FindIndexer(expr.Type, args, out var mb)) @@ -1975,8 +1979,9 @@ Expression ParseElementAccess(Expression expr) case 0: throw ParseError(errorPos, Res.NoApplicableIndexer, TypeHelper.GetTypeName(expr.Type)); + case 1: - var indexMethod = (MethodInfo)mb; + var indexMethod = (MethodInfo)mb!; var indexParameterType = indexMethod.GetParameters().First().ParameterType; var indexArgumentExpression = args[0]; // Indexer only has 1 parameter, so we can use args[0] here @@ -2004,7 +2009,7 @@ internal static Type ToNullableType(Type type) return typeof(Nullable<>).MakeGenericType(type); } - static bool TryGetMemberName(Expression expression, out string memberName) + private static bool TryGetMemberName(Expression expression, out string? memberName) { var memberExpression = expression as MemberExpression; if (memberExpression == null && expression.NodeType == ExpressionType.Coalesce) @@ -2030,7 +2035,7 @@ static bool TryGetMemberName(Expression expression, out string memberName) return false; } - void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) + private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) { Expression[] args = { expr }; @@ -2042,7 +2047,7 @@ void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, expr = args[0]; } - static string GetOverloadedOperationName(TokenId tokenId) + private static string? GetOverloadedOperationName(TokenId tokenId) { switch (tokenId) { @@ -2056,7 +2061,7 @@ static string GetOverloadedOperationName(TokenId tokenId) } } - void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) + private void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref Expression left, ref Expression right, int errorPos) { Expression[] args = { left, right }; @@ -2083,12 +2088,12 @@ void CheckAndPromoteOperands(Type signatures, TokenId opId, string opName, ref E right = args[1]; } - static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) + private static Exception IncompatibleOperandError(string opName, Expression expr, int errorPos) { return ParseError(errorPos, Res.IncompatibleOperand, opName, TypeHelper.GetTypeName(expr.Type)); } - static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) + private static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int errorPos) { return ParseError(errorPos, Res.IncompatibleOperands, opName, TypeHelper.GetTypeName(left.Type), TypeHelper.GetTypeName(right.Type)); } @@ -2132,12 +2137,12 @@ static Exception IncompatibleOperandsError(string opName, Expression left, Expre #endif } - bool TokenIdentifierIs(string id) + private bool TokenIdentifierIs(string id) { return _textParser.CurrentToken.Id == TokenId.Identifier && string.Equals(id, _textParser.CurrentToken.Text, StringComparison.OrdinalIgnoreCase); } - string GetIdentifier() + private string GetIdentifier() { _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected); string id = _textParser.CurrentToken.Text; @@ -2149,14 +2154,14 @@ string GetIdentifier() return id; } - Exception ParseError(string format, params object[] args) + private Exception ParseError(string format, params object[] args) { - return ParseError(_textParser?.CurrentToken.Pos ?? 0, format, args); + return ParseError(_textParser.CurrentToken.Pos, format, args); } - static Exception ParseError(int pos, string format, params object[] args) + private static Exception ParseError(int pos, string format, params object[] args) { return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs index cd30ae31..30a591cf 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeHelper.cs @@ -377,8 +377,13 @@ private static int GetNumericTypeKind(Type type) #endif } - public static string GetTypeName(Type type) + public static string GetTypeName(Type? type) { + if (type == null) + { + return "null"; + } + Type baseType = GetNonNullableType(type); string name = baseType.Name; diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs index 4fdadd0a..4a317f9f 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.ComponentModel; +using System.ComponentModel; using System.Linq.Dynamic.Core.Parser; using System.Linq.Dynamic.Core.Validation; @@ -9,11 +8,9 @@ internal class TypeConverterFactory : ITypeConverterFactory { private readonly ParsingConfig _config; - public TypeConverterFactory([NotNull] ParsingConfig config) + public TypeConverterFactory(ParsingConfig config) { - Check.NotNull(config, nameof(config)); - - _config = config; + _config = Check.NotNull(config, nameof(config)); } /// From 925ed812d6ddcec058a7e72970327585afd38522 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 21 Oct 2022 18:58:43 +0200 Subject: [PATCH 7/9] . --- ...amicQueryableWithFormattableStringExtensions.cs | 9 ++++++--- .../Parser/ConstantExpressionHelper.cs | 8 ++++---- .../Parser/ExpressionPromoter.cs | 14 +++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs index eb0ae3a7..8cc57e0b 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableWithFormattableStringExtensions.cs @@ -1,4 +1,6 @@ -using System.Collections; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System.Collections; using System.Text.RegularExpressions; using JetBrains.Annotations; @@ -12,7 +14,7 @@ namespace System.Linq.Dynamic.Core /// public static class DynamicQueryableWithFormattableStringExtensions { - private static Regex ReplaceArgumentsRegex = new Regex(@"{(\d+)}", RegexOptions.Compiled); + private static readonly Regex ReplaceArgumentsRegex = new(@"{(\d+)}", RegexOptions.Compiled); public static IQueryable WhereInterpolated([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] FormattableString predicate) { @@ -426,4 +428,5 @@ private static string ParseFormattableString(FormattableString predicate, out ob } } #endif -} \ No newline at end of file +} +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs index 60ef44f4..5b651651 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ConstantExpressionHelper.cs @@ -5,15 +5,15 @@ namespace System.Linq.Dynamic.Core.Parser { internal static class ConstantExpressionHelper { - private static readonly ConcurrentDictionary Expressions = new ConcurrentDictionary(); - private static readonly ConcurrentDictionary Literals = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Expressions = new(); + private static readonly ConcurrentDictionary Literals = new(); - public static bool TryGetText(Expression expression, out string text) + public static bool TryGetText(Expression expression, out string? text) { return Literals.TryGetValue(expression, out text); } - public static Expression CreateLiteral(object? value, string text) + public static Expression CreateLiteral(object value, string text) { if (!Expressions.ContainsKey(value)) { diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs index ca90207b..fea5eb2f 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionPromoter.cs @@ -38,7 +38,7 @@ public ExpressionPromoter(ParsingConfig config) } else { - if (ConstantExpressionHelper.TryGetText(ce, out string text)) + if (ConstantExpressionHelper.TryGetText(ce, out var text)) { Type target = TypeHelper.GetNonNullableType(type); object? value = null; @@ -50,7 +50,7 @@ public ExpressionPromoter(ParsingConfig config) case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); // Make sure an enum value stays an enum value if (target.IsEnum) @@ -62,12 +62,12 @@ public ExpressionPromoter(ParsingConfig config) case TypeCode.Double: if (target == typeof(decimal) || target == typeof(double)) { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } break; case TypeCode.String: - value = TypeHelper.ParseEnum(text, target); + value = TypeHelper.ParseEnum(text!, target); break; } #else @@ -80,19 +80,19 @@ public ExpressionPromoter(ParsingConfig config) } else { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } } else if (ce.Type == typeof(double)) { if (target == typeof(decimal) || target == typeof(double)) { - value = _numberParser.ParseNumber(text, target); + value = _numberParser.ParseNumber(text!, target); } } else if (ce.Type == typeof(string)) { - value = TypeHelper.ParseEnum(text, target); + value = TypeHelper.ParseEnum(text!, target); } #endif if (value != null) From 1ab6cfdbfc879319668a5c3dddb1b2ee22d36a8d Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 22 Oct 2022 11:03:52 +0200 Subject: [PATCH 8/9] . --- System.Linq.Dynamic.Core.sln.DotSettings | 1 + .../Compatibility/ExpressionVisitor.cs | 50 ++--- .../Compatibility/StringExtensions.cs | 27 +++ .../DynamicClassFactory.cs | 39 ++-- .../DynamicEnumerableAsyncExtensions.cs | 1 + .../DynamicEnumerableExtensions.cs | 51 ++--- .../DynamicQueryableExtensions.cs | 52 ++--- .../Parser/NumberParser.cs | 8 +- .../CallerArgumentExpressionAttribute.cs | 15 ++ .../Validation/Check.cs | 185 ++++++++---------- .../Validation/CoreStrings.cs | 49 ++--- 11 files changed, 240 insertions(+), 238 deletions(-) create mode 100644 src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs create mode 100644 src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs diff --git a/System.Linq.Dynamic.Core.sln.DotSettings b/System.Linq.Dynamic.Core.sln.DotSettings index 397fb4cf..13649a33 100644 --- a/System.Linq.Dynamic.Core.sln.DotSettings +++ b/System.Linq.Dynamic.Core.sln.DotSettings @@ -1,5 +1,6 @@  EF + IL UTC WASM True diff --git a/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs b/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs index 475cdd7b..3f1cd563 100644 --- a/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs +++ b/src/System.Linq.Dynamic.Core/Compatibility/ExpressionVisitor.cs @@ -19,7 +19,9 @@ protected ExpressionVisitor() protected virtual Expression Visit(Expression exp) { if (exp == null) + { return exp; + } switch (exp.NodeType) { @@ -103,7 +105,7 @@ protected virtual MemberBinding VisitBinding(MemberBinding binding) protected virtual ElementInit VisitElementInitializer(ElementInit initializer) { - ReadOnlyCollection arguments = this.VisitExpressionList(initializer.Arguments); + ReadOnlyCollection arguments = VisitExpressionList(initializer.Arguments); if (arguments != initializer.Arguments) { return Expression.ElementInit(initializer.AddMethod, arguments); @@ -127,13 +129,15 @@ protected virtual Expression VisitBinary(BinaryExpression b) { Expression left = Visit(b.Left); Expression right = Visit(b.Right); - Expression conversion = Visit(b.Conversion); + Expression conversion = Visit(b.Conversion!); if (left != b.Left || right != b.Right || conversion != b.Conversion) { if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + { return Expression.Coalesce(left, right, conversion as LambdaExpression); - else - return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); } return b; @@ -186,8 +190,8 @@ protected virtual Expression VisitMemberAccess(MemberExpression m) protected virtual Expression VisitMethodCall(MethodCallExpression m) { - Expression obj = Visit(m.Object); - IEnumerable args = this.VisitExpressionList(m.Arguments); + Expression obj = Visit(m.Object!); + IEnumerable args = VisitExpressionList(m.Arguments); if (obj != m.Object || args != m.Arguments) { return Expression.Call(obj, m.Method, args); @@ -198,10 +202,10 @@ protected virtual Expression VisitMethodCall(MethodCallExpression m) protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - Expression p = this.Visit(original[i]); + Expression p = Visit(original[i]); if (list != null) { list.Add(p); @@ -239,7 +243,7 @@ protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assign protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) { - IEnumerable bindings = this.VisitBindingList(binding.Bindings); + IEnumerable bindings = VisitBindingList(binding.Bindings); if (bindings != binding.Bindings) { return Expression.MemberBind(binding.Member, bindings); @@ -250,7 +254,7 @@ protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBindi protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) { - IEnumerable initializers = this.VisitElementInitializerList(binding.Initializers); + IEnumerable initializers = VisitElementInitializerList(binding.Initializers); if (initializers != binding.Initializers) { return Expression.ListBind(binding.Member, initializers); @@ -261,10 +265,10 @@ protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding bin protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - MemberBinding b = this.VisitBinding(original[i]); + MemberBinding b = VisitBinding(original[i]); if (list != null) { list.Add(b); @@ -288,10 +292,10 @@ protected virtual IEnumerable VisitBindingList(ReadOnlyCollection protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) { - List list = null; + List? list = null; for (int i = 0, n = original.Count; i < n; i++) { - ElementInit init = this.VisitElementInitializer(original[i]); + ElementInit init = VisitElementInitializer(original[i]); if (list != null) { list.Add(init); @@ -326,7 +330,7 @@ protected virtual Expression VisitLambda(LambdaExpression lambda) protected virtual NewExpression VisitNew(NewExpression nex) { - IEnumerable args = this.VisitExpressionList(nex.Arguments); + IEnumerable args = VisitExpressionList(nex.Arguments); if (args != nex.Arguments) { if (nex.Members != null) @@ -341,7 +345,7 @@ protected virtual NewExpression VisitNew(NewExpression nex) protected virtual Expression VisitMemberInit(MemberInitExpression init) { NewExpression n = VisitNew(init.NewExpression); - IEnumerable bindings = this.VisitBindingList(init.Bindings); + IEnumerable bindings = VisitBindingList(init.Bindings); if (n != init.NewExpression || bindings != init.Bindings) { return Expression.MemberInit(n, bindings); @@ -353,7 +357,7 @@ protected virtual Expression VisitMemberInit(MemberInitExpression init) protected virtual Expression VisitListInit(ListInitExpression init) { NewExpression n = VisitNew(init.NewExpression); - IEnumerable initializers = this.VisitElementInitializerList(init.Initializers); + IEnumerable initializers = VisitElementInitializerList(init.Initializers); if (n != init.NewExpression || initializers != init.Initializers) { return Expression.ListInit(n, initializers); @@ -364,17 +368,15 @@ protected virtual Expression VisitListInit(ListInitExpression init) protected virtual Expression VisitNewArray(NewArrayExpression na) { - IEnumerable exprs = this.VisitExpressionList(na.Expressions); + IEnumerable exprs = VisitExpressionList(na.Expressions); if (exprs != na.Expressions) { if (na.NodeType == ExpressionType.NewArrayInit) { - return Expression.NewArrayInit(na.Type.GetElementType(), exprs); - } - else - { - return Expression.NewArrayBounds(na.Type.GetElementType(), exprs); + return Expression.NewArrayInit(na.Type.GetElementType()!, exprs); } + + return Expression.NewArrayBounds(na.Type.GetElementType()!, exprs); } return na; @@ -382,7 +384,7 @@ protected virtual Expression VisitNewArray(NewArrayExpression na) protected virtual Expression VisitInvocation(InvocationExpression iv) { - IEnumerable args = this.VisitExpressionList(iv.Arguments); + IEnumerable args = VisitExpressionList(iv.Arguments); Expression expr = Visit(iv.Expression); if (args != iv.Arguments || expr != iv.Expression) { diff --git a/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs new file mode 100644 index 00000000..a97cd4d0 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs @@ -0,0 +1,27 @@ +// ReSharper disable once CheckNamespace +namespace System; + +internal static class StringExtensions +{ + public static bool IsNullOrWhiteSpace(this string? value) + { +#if !NET35 + return string.IsNullOrWhiteSpace(value); +#else + if (value == null) + { + return true; + } + + for (int i = 0; i < value.Length; i++) + { + if (!char.IsWhiteSpace(value[i])) + { + return false; + } + } + + return true; +#endif + } +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs b/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs index abbb7545..d705ffe3 100644 --- a/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs +++ b/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs @@ -22,20 +22,20 @@ namespace System.Linq.Dynamic.Core /// public static class DynamicClassFactory { - private static readonly ConcurrentDictionary GeneratedTypes = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary GeneratedTypes = new(); private static readonly ModuleBuilder ModuleBuilder; // Some objects we cache - private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]); - private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never }); - private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]); + private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]); + private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never }); + private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]); - private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes); + private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes)!; #if WINDOWS_APP || UAP10_0 || NETSTANDARD - private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public); + private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public)!; #else - private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); + private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null)!; #endif private static readonly ConstructorInfo StringBuilderCtor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes); @@ -43,20 +43,20 @@ public static class DynamicClassFactory private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", new[] { typeof(string) }); private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", new[] { typeof(object) }); #else - private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); - private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null); + private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null)!; + private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null)!; #endif private static readonly Type EqualityComparer = typeof(EqualityComparer<>); private static readonly Type EqualityComparerGenericArgument = EqualityComparer.GetGenericArguments()[0]; #if WINDOWS_APP || UAP10_0 || NETSTANDARD - private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public); - private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }); - private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", new[] { EqualityComparerGenericArgument }); + private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public)!; + private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument })!; + private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", new[] { EqualityComparerGenericArgument })!; #else - private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); - private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null); - private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null); + private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null)!; + private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null)!; + private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null)!; #endif private static int _index = -1; @@ -105,9 +105,9 @@ public static Type CreateGenericComparerType(Type comparerGenericType, Type comp { if (!GeneratedTypes.TryGetValue(key, out type)) { - var compareMethodGeneric = comparerGenericType.GetMethod("Compare"); + var compareMethodGeneric = comparerGenericType.GetMethod("Compare")!; var compareMethod = typeof(IComparer).GetMethod("Compare"); - var compareCtor = comparerType.GetConstructor(Type.EmptyTypes); + var compareCtor = comparerType.GetConstructor(Type.EmptyTypes)!; var genericType = comparerGenericType.GetGenericArguments()[0]; var typeBuilder = ModuleBuilder.DefineType(key, TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoLayout, typeof(object)); @@ -170,7 +170,7 @@ public static Type CreateGenericComparerType(Type comparerGenericType, Type comp /// ]]> /// /// - public static Type CreateType([NotNull] IList properties, bool createParameterCtor = true) + public static Type CreateType(IList properties, bool createParameterCtor = true) { Check.HasNoNulls(properties, nameof(properties)); @@ -179,8 +179,7 @@ public static Type CreateType([NotNull] IList properties, bool string key = GenerateKey(properties, createParameterCtor); - Type type; - if (!GeneratedTypes.TryGetValue(key, out type)) + if (!GeneratedTypes.TryGetValue(key, out var type)) { // We create only a single class at a time, through this lock // Note that this is a variant of the double-checked locking. diff --git a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs index 97faa375..b23d3215 100644 --- a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs @@ -117,6 +117,7 @@ public static Task> ToDynamicListAsync(this IEnumerable source, Cance } #pragma warning disable CS1998 + // ReSharper disable once UnusedParameter.Local private static async Task> ToListAsync(IEnumerable source, CancellationToken cancellationToken) #pragma warning restore CS1998 { diff --git a/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs index 85bc93b7..b669fafe 100644 --- a/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Linq.Dynamic.Core.Validation; using System.Reflection; @@ -25,16 +24,14 @@ static DynamicEnumerableExtensions() /// A to create an array from. /// An array that contains the elements from the input sequence. #if NET35 - public static object[] ToDynamicArray([NotNull] this IEnumerable source) + public static object[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } #else - public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source) + public static dynamic[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } #endif @@ -44,10 +41,9 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source) /// The generic type. /// A to create an array from. /// An Array{T} that contains the elements from the input sequence. - public static T[] ToDynamicArray([NotNull] this IEnumerable source) + public static T[] ToDynamicArray(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToArray(source); + return CastToArray(Check.NotNull(source)); } /// @@ -57,13 +53,13 @@ public static T[] ToDynamicArray([NotNull] this IEnumerable source) /// A cast to. /// An Array that contains the elements from the input sequence. #if NET35 - public static object[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type) + public static object[] ToDynamicArray(this IEnumerable source, Type type) #else - public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNull] Type type) + public static dynamic[] ToDynamicArray(this IEnumerable source, Type type) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); IEnumerable result = (IEnumerable)ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source }); #if NET35 @@ -79,16 +75,15 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNu /// A to create an array from. /// A List that contains the elements from the input sequence. #if NET35 - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) #else - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) #endif { - Check.NotNull(source, nameof(source)); #if NET35 - return CastToList(source); + return CastToList(Check.NotNull(source)); #else - return CastToList(source); + return CastToList(Check.NotNull(source)); #endif } @@ -99,15 +94,12 @@ public static List ToDynamicList([NotNull] this IEnumerable source) /// A cast to. /// A List that contains the elements from the input sequence. #if NET35 - public static List ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type) + public static List ToDynamicList(this IEnumerable source, Type type) #else - public static List ToDynamicList([NotNull] this IEnumerable source, [NotNull] Type type) + public static List ToDynamicList(this IEnumerable source, Type type) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); - - return ToDynamicArray(source, type).ToList(); + return ToDynamicArray(Check.NotNull(source), Check.NotNull(type)).ToList(); } /// @@ -116,10 +108,9 @@ public static List ToDynamicList([NotNull] this IEnumerable source, [No /// Generic Type /// A to create an array from. /// A List{T} that contains the elements from the input sequence. - public static List ToDynamicList([NotNull] this IEnumerable source) + public static List ToDynamicList(this IEnumerable source) { - Check.NotNull(source, nameof(source)); - return CastToList(source); + return CastToList(Check.NotNull(source)); } internal static T[] CastToArray(IEnumerable source) @@ -132,4 +123,4 @@ internal static List CastToList(IEnumerable source) return source.Cast().ToList(); } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index d4e27c7f..bde0b809 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -57,25 +57,25 @@ private static Expression OptimizeExpression(Expression expression) /// The name of the function to run. Can be Sum, Average, Min or Max. /// The name of the property to aggregate over. /// The value of the aggregate function run over the specified property. - public static object Aggregate([NotNull] this IQueryable source, [NotNull] string function, [NotNull] string member) + public static object Aggregate(this IQueryable source, string function, string member) { - Check.NotNull(source, nameof(source)); - Check.NotEmpty(function, nameof(function)); - Check.NotEmpty(member, nameof(member)); + Check.NotNull(source); + Check.NotEmpty(function); + Check.NotEmpty(member); // Properties - PropertyInfo property = source.ElementType.GetProperty(member); + PropertyInfo property = source.ElementType.GetProperty(member)!; ParameterExpression parameter = ParameterExpressionHelper.CreateParameterExpression(source.ElementType, "s"); Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, property), parameter); // We've tried to find an expression of the type Expression>, // which is expressed as ( (TSource s) => s.Price ); - var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function && x.IsGenericMethod); + var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function && x.IsGenericMethod).ToArray(); // Method - MethodInfo aggregateMethod = methods.SingleOrDefault(m => + MethodInfo? aggregateMethod = methods.SingleOrDefault(m => { - ParameterInfo lastParameter = m.GetParameters().LastOrDefault(); + var lastParameter = m.GetParameters().LastOrDefault(); return lastParameter != null && TypeHelper.GetUnderlyingType(lastParameter.ParameterType) == property.PropertyType; }); @@ -96,7 +96,7 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin return source.Provider.Execute( Expression.Call( null, - aggregateMethod.MakeGenericMethod(source.ElementType, property.PropertyType), + aggregateMethod!.MakeGenericMethod(source.ElementType, property.PropertyType), new[] { source.Expression, Expression.Quote(selector) })); } #endregion Aggregate @@ -110,7 +110,7 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static bool All(this IQueryable source, string predicate, params object?[]? args) { return All(source, ParsingConfig.Default, predicate, args); } @@ -122,11 +122,11 @@ public static bool All([NotNull] this IQueryable source, [NotNull] string predic /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static bool All(this IQueryable source, ParsingConfig config, string predicate, params object?[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(createParameterCtor, source.ElementType, null, predicate, args); @@ -813,7 +813,7 @@ internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args); - Expression optimized = null; + Expression? optimized = null; if (equalityComparer == null) { @@ -1427,12 +1427,12 @@ public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpre /// An whose elements to filter. /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type type) + public static IQueryable OfType(this IQueryable source, Type type) { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); - var optimized = OptimizeExpression(Expression.Call(null, _ofType.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression })); + var optimized = OptimizeExpression(Expression.Call(null, _ofType.MakeGenericMethod(type), new[] { source.Expression })); return source.Provider.CreateQuery(optimized); } @@ -1444,14 +1444,14 @@ public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Type /// The . /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) + public static IQueryable OfType(this IQueryable source, ParsingConfig config, string typeName) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(typeName, nameof(typeName)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(typeName); var finder = new TypeFinder(config, new KeywordsHelper(config)); - Type type = finder.FindTypeByName(typeName, null, true); + Type type = finder.FindTypeByName(typeName, null, true)!; return OfType(source, type); } @@ -1462,7 +1462,7 @@ public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] Pars /// An whose elements to filter. /// The type to filter the elements of the sequence on. /// A collection that contains the elements from source that have the type. - public static IQueryable OfType([NotNull] this IQueryable source, [NotNull] string typeName) + public static IQueryable OfType(this IQueryable source, string typeName) { return OfType(source, ParsingConfig.Default, typeName); } @@ -1703,7 +1703,7 @@ public static PagedResult PageResult([NotNull] this IQueryable source, int page, /// The number of elements per page. /// If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq `Count()`. /// PagedResult{TSource} - public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize, int? rowCount = null) + public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) { Check.NotNull(source, nameof(source)); Check.Condition(page, p => p > 0, nameof(page)); diff --git a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs index 8efa9cd6..3c65bcad 100644 --- a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs @@ -163,18 +163,18 @@ public Expression ParseRealLiteral(string text, char qualifier, bool stripQualif { case 'f': case 'F': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(float)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(float))!, text); case 'm': case 'M': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(decimal)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(decimal))!, text); case 'd': case 'D': - return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(double)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(double))!, text); default: - return ConstantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double)), text); + return ConstantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double))!, text); } } diff --git a/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs b/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs new file mode 100644 index 00000000..96fa84d3 --- /dev/null +++ b/src/System.Linq.Dynamic.Core/Validation/CallerArgumentExpressionAttribute.cs @@ -0,0 +1,15 @@ +#if !NETCOREAPP3_0_OR_GREATER +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string parameterName) + { + ParameterName = parameterName; + } + + public string ParameterName { get; } + } +} +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Validation/Check.cs b/src/System.Linq.Dynamic.Core/Validation/Check.cs index b58e16e8..a1c36983 100644 --- a/src/System.Linq.Dynamic.Core/Validation/Check.cs +++ b/src/System.Linq.Dynamic.Core/Validation/Check.cs @@ -1,136 +1,123 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; -using JetBrains.Annotations; -// using System.Reflection; +using System.Runtime.CompilerServices; + +// Copied from https://github.com/StefH/Stef.Validation +namespace System.Linq.Dynamic.Core.Validation; -// Copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Shared/Check.cs -namespace System.Linq.Dynamic.Core.Validation +[DebuggerStepThrough] +internal static class Check { - [DebuggerStepThrough] - internal static class Check + public static T Condition(T value, Predicate predicate, [CallerArgumentExpression("value")] string? parameterName = null) { - public static T Condition([ValidatedNotNull, NoEnumeration] T value, [ValidatedNotNull, NotNull] Predicate condition, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) + NotNull(predicate, nameof(predicate)); + + if (!predicate(value)) { - NotNull(condition, nameof(condition)); + NotNullOrEmpty(parameterName, nameof(parameterName)); + + throw new ArgumentOutOfRangeException(parameterName); + } - if (!condition(value)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentOutOfRangeException(parameterName); - } + public static T NotNull(T value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - return value; + throw new ArgumentNullException(parameterName); } - [ContractAnnotation("value:null => halt")] - public static T NotNull([ValidatedNotNull, NoEnumeration] T value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - { - if (ReferenceEquals(value, null)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentNullException(parameterName); - } + public static T NotNull(T value, string parameterName, string propertyName) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); + NotNullOrEmpty(propertyName, nameof(propertyName)); - return value; + throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName)); } - [ContractAnnotation("value:null => halt")] - public static T NotNull( - [NoEnumeration] T value, - [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName, - [ValidatedNotNull, NotNull] string propertyName) - { - if (ReferenceEquals(value, null)) - { - NotEmpty(parameterName, nameof(parameterName)); - NotEmpty(propertyName, nameof(propertyName)); + return value; + } - throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName)); - } + public static IEnumerable NotNullOrEmpty(IEnumerable value, [CallerArgumentExpression("value")] string? parameterName = null) + { + IEnumerable result = NotNull(value, parameterName); - return value; + // ReSharper disable once PossibleMultipleEnumeration + if (!result.Any()) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); + + throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName)); } - //[ContractAnnotation("value:null => halt")] - //public static IList NotEmpty(IList value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // NotNull(value, parameterName); + // ReSharper disable once PossibleMultipleEnumeration + return result; + } - // if (value.Count == 0) - // { - // NotEmpty(parameterName, nameof(parameterName)); + public static string NotEmpty(string? value, [CallerArgumentExpression("value")] string? parameterName = null) => + NotNullOrWhiteSpace(value, parameterName); - // throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName)); - // } + public static string NotNullOrEmpty(string? value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // return value; - //} + throw new ArgumentNullException(parameterName); + } - [ContractAnnotation("value:null => halt")] - public static string NotEmpty(string value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) + if (string.IsNullOrEmpty(value)) { - Exception e = null; - if (ReferenceEquals(value, null)) - { - e = new ArgumentNullException(parameterName); - } - else if (value.Trim().Length == 0) - { - e = new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); - } - - if (e != null) - { - NotEmpty(parameterName, nameof(parameterName)); - - throw e; - } - - return value; + throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); } - //public static string NullButNotEmpty(string value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // if (!ReferenceEquals(value, null) && value.Length == 0) - // { - // NotEmpty(parameterName, nameof(parameterName)); + return value; + } - // throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); - // } + public static string NotNullOrWhiteSpace(string? value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // return value; - //} + throw new ArgumentNullException(parameterName); + } - public static IList HasNoNulls(IList value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - where T : class + if (value.IsNullOrWhiteSpace()) { - NotNull(value, parameterName); + throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName)); + } - if (value.Any(e => e == null)) - { - NotEmpty(parameterName, nameof(parameterName)); + return value; + } - throw new ArgumentException(parameterName); - } + public static IEnumerable HasNoNulls(IEnumerable value, [CallerArgumentExpression("value")] string? parameterName = null) + { + if (value is null) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - return value; + throw new ArgumentNullException(parameterName); } - //public static Type ValidEntityType(Type value, [InvokerParameterName, ValidatedNotNull, NotNull] string parameterName) - //{ - // if (!value.GetTypeInfo().IsClass) - // { - // NotEmpty(parameterName, nameof(parameterName)); + // ReSharper disable once PossibleMultipleEnumeration + if (value.Any(v => v is null)) + { + NotNullOrEmpty(parameterName, nameof(parameterName)); - // throw new ArgumentException(CoreStrings.InvalidEntityType(value, parameterName)); - // } + throw new ArgumentException(parameterName); + } - // return value; - //} + // ReSharper disable once PossibleMultipleEnumeration + return value; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs b/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs index d5570cad..c5f68b1b 100644 --- a/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs +++ b/src/System.Linq.Dynamic.Core/Validation/CoreStrings.cs @@ -1,41 +1,20 @@ -using System.Globalization; -using JetBrains.Annotations; +// Copied from https://github.com/StefH/Stef.Validation +namespace System.Linq.Dynamic.Core.Validation; -// copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Properties/CoreStrings.resx -namespace System.Linq.Dynamic.Core.Validation +internal static class CoreStrings { - internal static class CoreStrings + public static string ArgumentPropertyNull(string property, string argument) { - /// - /// The property '{property}' of the argument '{argument}' cannot be null. - /// - public static string ArgumentPropertyNull([CanBeNull] string property, [CanBeNull] string argument) - { - return string.Format(CultureInfo.CurrentCulture, "The property '{0}' of the argument '{1}' cannot be null.", property, argument); - } - - /// - /// The string argument '{argumentName}' cannot be empty. - /// - public static string ArgumentIsEmpty([CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The string argument '{0}' cannot be empty.", argumentName); - } + return $"The property '{property}' of the argument '{argument}' cannot be null."; + } - /// - /// The entity type '{type}' provided for the argument '{argumentName}' must be a reference type. - /// - public static string InvalidEntityType([CanBeNull] Type type, [CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The entity type '{0}' provided for the argument '{1}' must be a reference type.", type, argumentName); - } + public static string ArgumentIsEmpty(string? argumentName) + { + return $"Value cannot be empty. (Parameter '{argumentName}')"; + } - /// - /// The collection argument '{argumentName}' must contain at least one element. - /// - public static string CollectionArgumentIsEmpty([CanBeNull] string argumentName) - { - return string.Format(CultureInfo.CurrentCulture, "The collection argument '{0}' must contain at least one element.", argumentName); - } + public static string CollectionArgumentIsEmpty(string? argumentName) + { + return $"The collection argument '{argumentName}' must contain at least one element."; } -} +} \ No newline at end of file From 6f59aae27d1a2c6201ed6fde518318d21aa0b512 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 23 Oct 2022 10:45:43 +0200 Subject: [PATCH 9/9] . --- ...ueryableWithFormattableStringExtensions.cs | 1 + .../Compatibility/StringExtensions.cs | 12 + .../DefaultQueryableAnalyzer.cs | 95 ++- .../DynamicEnumerableAsyncExtensions.cs | 214 +++--- .../DynamicExpressionParser.cs | 6 +- .../DynamicGetMemberBinder.cs | 91 ++- .../DynamicQueryableExtensions.cs | 631 +++++++++--------- src/System.Linq.Dynamic.Core/GroupResult.cs | 6 +- .../IQueryableAnalyzer.cs | 25 +- .../ParameterExpressionHelper.cs | 66 +- .../Parser/Constants.cs | 13 +- .../Parser/ExpressionHelper.cs | 12 +- .../Parser/NumberParser.cs | 10 +- .../Parser/TypeFinder.cs | 6 +- .../TypeConverters/CustomDateTimeConverter.cs | 31 +- .../TypeConverters/ITypeConverterFactory.cs | 24 +- .../TypeConverters/TypeConverterFactory.cs | 6 +- .../Util/ParameterExpressionRenamer.cs | 108 ++- .../Util/QueryableMethodFinder.cs | 65 +- .../Parser/ParameterExpressionHelperTests.cs | 2 +- 20 files changed, 694 insertions(+), 730 deletions(-) diff --git a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs index aa2e2433..2a75ae60 100644 --- a/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs +++ b/src/Microsoft.EntityFrameworkCore.DynamicLinq.EFCore3/EFDynamicQueryableWithFormattableStringExtensions.cs @@ -13,6 +13,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +#pragma warning disable CS1591 using JetBrains.Annotations; using System.Text.RegularExpressions; diff --git a/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs index a97cd4d0..c84575fe 100644 --- a/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs +++ b/src/System.Linq.Dynamic.Core/Compatibility/StringExtensions.cs @@ -3,6 +3,18 @@ namespace System; internal static class StringExtensions { + /// + /// Indicates whether a specified string is null, empty, or consists only of white-space + /// characters. + /// + /// Recreates the same functionality as System.String.IsNullOrWhiteSpace but included here + /// for compatibility with net35. + /// + /// The string to test. + /// + /// true if the value parameter is null or System.String.Empty, or if value consists + /// exclusively of white-space characters. + /// public static bool IsNullOrWhiteSpace(this string? value) { #if !NET35 diff --git a/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs b/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs index a9136777..9c637f22 100644 --- a/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs +++ b/src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs @@ -1,71 +1,68 @@ using System.Linq.Dynamic.Core.Validation; using System.Reflection; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Default implementation. +/// +/// +public class DefaultQueryableAnalyzer : IQueryableAnalyzer { - /// - /// Default implementation. - /// - /// - public class DefaultQueryableAnalyzer : IQueryableAnalyzer + /// + public bool SupportsLinqToObjects(IQueryable query, IQueryProvider? provider = null) { - /// - public bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null) - { - Check.NotNull(query, nameof(query)); - provider = provider ?? query.Provider; + Check.NotNull(query, nameof(query)); + provider = provider ?? query.Provider; - Type providerType = provider.GetType(); - Type baseType = providerType.GetTypeInfo().BaseType; + Type providerType = provider.GetType(); + Type baseType = providerType.GetTypeInfo().BaseType!; #if NET35 - bool isLinqToObjects = baseType.FullName.Contains("EnumerableQuery"); + bool isLinqToObjects = baseType.FullName!.Contains("EnumerableQuery"); #else - bool isLinqToObjects = baseType == typeof(EnumerableQuery); + bool isLinqToObjects = baseType == typeof(EnumerableQuery); #endif - if (!isLinqToObjects) + if (!isLinqToObjects) + { + // Support for https://github.com/StefH/QueryInterceptor.Core, version 1.0.1 and up + if (providerType.Name.StartsWith("QueryTranslatorProvider")) { - // Support for https://github.com/StefH/QueryInterceptor.Core, version 1.0.1 and up - if (providerType.Name.StartsWith("QueryTranslatorProvider")) + try { - try - { - PropertyInfo property = providerType.GetProperty("OriginalProvider"); - if (property != null) - { - IQueryProvider originalProvider = property.GetValue(provider, null) as IQueryProvider; - return originalProvider != null && SupportsLinqToObjects(query, originalProvider); - } - - return SupportsLinqToObjects(query); - } - catch + var property = providerType.GetProperty("OriginalProvider"); + if (property != null) { - return false; + return property.GetValue(provider, null) is IQueryProvider originalProvider && SupportsLinqToObjects(query, originalProvider); } - } - // Support for https://github.com/scottksmith95/LINQKit ExpandableQuery - if (providerType.Name.StartsWith("ExpandableQuery")) + return SupportsLinqToObjects(query); + } + catch { - try - { - PropertyInfo property = query.GetType().GetProperty("InnerQuery", BindingFlags.NonPublic | BindingFlags.Instance); - if (property != null) - { - IQueryable innerQuery = property.GetValue(query, null) as IQueryable; - return innerQuery != null && SupportsLinqToObjects(innerQuery, provider); - } + return false; + } + } - return SupportsLinqToObjects(query); - } - catch + // Support for https://github.com/scottksmith95/LINQKit ExpandableQuery + if (providerType.Name.StartsWith("ExpandableQuery")) + { + try + { + var property = query.GetType().GetProperty("InnerQuery", BindingFlags.NonPublic | BindingFlags.Instance); + if (property != null) { - return false; + return property.GetValue(query, null) is IQueryable innerQuery && SupportsLinqToObjects(innerQuery, provider); } + + return SupportsLinqToObjects(query); + } + catch + { + return false; } } - - return isLinqToObjects; } + + return isLinqToObjects; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs index b23d3215..98b32d1b 100644 --- a/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicEnumerableAsyncExtensions.cs @@ -7,137 +7,129 @@ using System.Threading.Tasks; using JetBrains.Annotations; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Define async extensions on . +/// +public static class DynamicEnumerableAsyncExtensions { + private static readonly MethodInfo ToListAsyncGenericMethod; + + static DynamicEnumerableAsyncExtensions() + { + ToListAsyncGenericMethod = typeof(DynamicEnumerableAsyncExtensions).GetTypeInfo() + .GetDeclaredMethods("ToListAsync") + .First(x => x.IsGenericMethod); + } + /// - /// Define async extensions on . + /// Async creates an array of dynamic objects from a . /// - public static class DynamicEnumerableAsyncExtensions + /// A to create an array from. + /// A cast to. + /// The (optional). + /// An Array that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) { - private static readonly MethodInfo ToListAsyncGenericMethod; - - static DynamicEnumerableAsyncExtensions() - { - ToListAsyncGenericMethod = typeof(DynamicEnumerableAsyncExtensions).GetTypeInfo() - .GetDeclaredMethods("ToListAsync") - .First(x => x.IsGenericMethod); - } - - /// - /// Async creates an array of dynamic objects from a . - /// - /// A to create an array from. - /// A cast to. - /// The (optional). - /// An Array that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); - - var result = await ToDynamicListAsync(source, type, cancellationToken).ConfigureAwait(false); - return result.ToArray(); - } + var result = await ToDynamicListAsync(Check.NotNull(source), Check.NotNull(type), cancellationToken).ConfigureAwait(false); + return result.ToArray(); + } - /// - /// Async creates an array of dynamic objects from a . - /// - /// A to create an array from. - /// The (optional). - /// An array that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return (await ToListAsync(source, cancellationToken).ConfigureAwait(false)).ToArray(); - } + /// + /// Async creates an array of dynamic objects from a . + /// + /// A to create an array from. + /// The (optional). + /// An array that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return (await ToListAsync(Check.NotNull(source), cancellationToken).ConfigureAwait(false)).ToArray(); + } - /// - /// Async creates an array of dynamic objects from a . - /// - /// The generic type. - /// A to create an array from. - /// The (optional). - /// An Array{T} that contains the elements from the input sequence. - [PublicAPI] - public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return (await ToListAsync(source, cancellationToken).ConfigureAwait(false)).ToArray(); - } + /// + /// Async creates an array of dynamic objects from a . + /// + /// The generic type. + /// A to create an array from. + /// The (optional). + /// An Array{T} that contains the elements from the input sequence. + [PublicAPI] + public static async Task ToDynamicArrayAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return (await ToListAsync(Check.NotNull(source), cancellationToken).ConfigureAwait(false)).ToArray(); + } - /// - /// Async creates a list of dynamic objects from a . - /// - /// A to create an array from. - /// A cast to. - /// The (optional). - /// An List that contains the elements from the input sequence. - [PublicAPI] - public static async Task> ToDynamicListAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + /// + /// Async creates a list of dynamic objects from a . + /// + /// A to create an array from. + /// A cast to. + /// The (optional). + /// An List that contains the elements from the input sequence. + [PublicAPI] + public static async Task> ToDynamicListAsync(this IEnumerable source, Type type, CancellationToken cancellationToken = default) + { + Check.NotNull(source); + Check.NotNull(type); - var task = (Task)ToListAsyncGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source, cancellationToken })!; + var task = (Task)ToListAsyncGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source, cancellationToken })!; - await task.ConfigureAwait(false); + await task.ConfigureAwait(false); - var list = (IList)task.GetType().GetProperty(nameof(Task.Result))!.GetValue(task)!; + var list = (IList)task.GetType().GetProperty(nameof(Task.Result))!.GetValue(task)!; - return list.Cast().ToList(); - } + return list.Cast().ToList(); + } - /// - /// Async creates a list of dynamic objects from a . - /// - /// A to create a list from. - /// The (optional). - /// A List that contains the elements from the input sequence. - [PublicAPI] - public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return ToListAsync(source, cancellationToken); - } + /// + /// Async creates a list of dynamic objects from a . + /// + /// A to create a list from. + /// The (optional). + /// A List that contains the elements from the input sequence. + [PublicAPI] + public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return ToListAsync(Check.NotNull(source), cancellationToken); + } - /// - /// Async creates a list of dynamic objects from an . - /// - /// Generic Type - /// A to create a list from. - /// The (optional). - /// A List{T} that contains the elements from the input sequence. - [PublicAPI] - public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) - { - Check.NotNull(source, nameof(source)); - return ToListAsync(source, cancellationToken); - } + /// + /// Async creates a list of dynamic objects from an . + /// + /// Generic Type + /// A to create a list from. + /// The (optional). + /// A List{T} that contains the elements from the input sequence. + [PublicAPI] + public static Task> ToDynamicListAsync(this IEnumerable source, CancellationToken cancellationToken = default) + { + return ToListAsync(Check.NotNull(source), cancellationToken); + } #pragma warning disable CS1998 - // ReSharper disable once UnusedParameter.Local - private static async Task> ToListAsync(IEnumerable source, CancellationToken cancellationToken) + // ReSharper disable once UnusedParameter.Local + private static async Task> ToListAsync(IEnumerable source, CancellationToken cancellationToken) #pragma warning restore CS1998 + { + switch (source) { - switch (source) - { #if NETSTANDARD2_1_OR_GREATER || ASYNCENUMERABLE - case IAsyncEnumerable asyncEnumerable: - var list = new List(); - await foreach (var element in asyncEnumerable.WithCancellation(cancellationToken).ConfigureAwait(false)) - { - list.Add(element); - } - return list; + case IAsyncEnumerable asyncEnumerable: + var list = new List(); + await foreach (var element in asyncEnumerable.WithCancellation(cancellationToken).ConfigureAwait(false)) + { + list.Add(element); + } + return list; #endif - case IEnumerable enumerable: - return enumerable.ToList(); + case IEnumerable enumerable: + return enumerable.ToList(); - default: - return source.Cast().ToList(); - } + default: + return source.Cast().ToList(); } } } diff --git a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs index 06717c8f..c0629715 100644 --- a/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs @@ -93,7 +93,7 @@ public static Expression> ParseLambda(Type delegateType, /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]? values) { return ParseLambda(null, parsingConfig, createParameterCtor, parameters, resultType, expression, values); } @@ -110,7 +110,7 @@ public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool cr /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[] values) + public static LambdaExpression ParseLambda(Type? delegateType, ParsingConfig? parsingConfig, bool createParameterCtor, ParameterExpression[] parameters, Type? resultType, string expression, params object?[]? values) { Check.NotNull(parameters, nameof(parameters)); Check.HasNoNulls(parameters, nameof(parameters)); @@ -349,7 +349,7 @@ public static LambdaExpression ParseLambda(Type delegateType, ParsingConfig? par /// An object array that contains zero or more objects which are used as replacement values. /// The generated [PublicAPI] - public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[] values) + public static LambdaExpression ParseLambda(ParsingConfig? parsingConfig, bool createParameterCtor, Type itType, Type? resultType, string expression, params object?[]? values) { Check.NotNull(itType, nameof(itType)); Check.NotEmpty(expression, nameof(expression)); diff --git a/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs b/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs index 2b1b3f83..f2369f44 100644 --- a/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs +++ b/src/System.Linq.Dynamic.Core/DynamicGetMemberBinder.cs @@ -4,65 +4,64 @@ using System.Dynamic; using System.Linq.Expressions; using System.Reflection; -using JetBrains.Annotations; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +/// +/// Code is based on SqlLinq by dkackman (https://github.com/dkackman/SqlLinq/blob/210b594e37f14061424397368ed750ce547c21e7/License.md) however it's modified to solve several issues. +/// +/// +internal class DynamicGetMemberBinder : GetMemberBinder { - /// - /// Code is based on SqlLinq by dkackman (https://github.com/dkackman/SqlLinq/blob/210b594e37f14061424397368ed750ce547c21e7/License.md) however it's modified to solve several issues. - /// - /// - internal class DynamicGetMemberBinder : GetMemberBinder + private static readonly MethodInfo DynamicGetMemberMethod = typeof(DynamicGetMemberBinder).GetMethod(nameof(GetDynamicMember))!; + + public DynamicGetMemberBinder(string name, ParsingConfig? config) : base(name, config?.IsCaseSensitive != true) + { + } + + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { - private static readonly MethodInfo DynamicGetMemberMethod = typeof(DynamicGetMemberBinder).GetMethod(nameof(GetDynamicMember)); + var instance = Expression.Call( + DynamicGetMemberMethod, + target.Expression, + Expression.Constant(Name), + Expression.Constant(IgnoreCase)); - public DynamicGetMemberBinder(string name, [CanBeNull] ParsingConfig config) : base(name, !(config?.IsCaseSensitive == true)) + return DynamicMetaObject.Create(target.Value!, instance); + } + + public static object? GetDynamicMember(object value, string name, bool ignoreCase) + { + if (value == null) { + throw new InvalidOperationException(); } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + if (value is IDictionary stringObjectDictionary) { - var instance = Expression.Call( - DynamicGetMemberMethod, - target.Expression, - Expression.Constant(Name), - Expression.Constant(IgnoreCase)); - - return DynamicMetaObject.Create(target.Value, instance); + return stringObjectDictionary[name]; } - public static object GetDynamicMember(object value, string name, bool ignoreCase) + if (value is IDictionary nonGenericDictionary) { - if (value == null) - { - throw new InvalidOperationException(); - } - - if (value is IDictionary stringObjectDictionary) - { - return stringObjectDictionary[name]; - } - - if (value is IDictionary nonGenericDictionary) - { - return nonGenericDictionary[name]; - } - - var flags = BindingFlags.Instance | BindingFlags.Public; - if (ignoreCase) - { - flags |= BindingFlags.IgnoreCase; - } + return nonGenericDictionary[name]; + } - var type = value.GetType(); - var property = type.GetProperty(name, flags); - if (property == null) - { - throw new InvalidOperationException($"Unable to find property '{name}' on type '{type}'."); - } + var flags = BindingFlags.Instance | BindingFlags.Public; + if (ignoreCase) + { + flags |= BindingFlags.IgnoreCase; + } - return property.GetValue(value, null); + var type = value.GetType(); + var property = type.GetProperty(name, flags); + if (property == null) + { + throw new InvalidOperationException($"Unable to find property '{name}' on type '{type}'."); } + + return property.GetValue(value, null); } } -#endif + +#endif \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs index bde0b809..a9a72943 100644 --- a/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs +++ b/src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq.Dynamic.Core.Exceptions; #if !(WINDOWS_APP45x || SILVERLIGHT) @@ -24,10 +25,11 @@ namespace System.Linq.Dynamic.Core /// It allows dynamic string based querying. Very handy when, at compile time, you don't know the type of queries that will be generated, /// or when downstream components only return column names to sort and filter by. /// + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] public static class DynamicQueryableExtensions { #if !(WINDOWS_APP45x || SILVERLIGHT) - private static readonly TraceSource TraceSource = new TraceSource(nameof(DynamicQueryableExtensions)); + private static readonly TraceSource TraceSource = new(nameof(DynamicQueryableExtensions)); #endif private static Expression OptimizeExpression(Expression expression) @@ -87,7 +89,7 @@ public static object Aggregate(this IQueryable source, string function, string m Expression.Call( null, aggregateMethod.MakeGenericMethod(source.ElementType), - new[] { source.Expression, Expression.Quote(selector) })); + new[] { source.Expression, Expression.Quote(selector) }))!; } // Min, Max @@ -97,7 +99,7 @@ public static object Aggregate(this IQueryable source, string function, string m Expression.Call( null, aggregateMethod!.MakeGenericMethod(source.ElementType, property.PropertyType), - new[] { source.Expression, Expression.Quote(selector) })); + new[] { source.Expression, Expression.Quote(selector) }))!; } #endregion Aggregate @@ -110,7 +112,7 @@ public static object Aggregate(this IQueryable source, string function, string m /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All(this IQueryable source, string predicate, params object?[]? args) + public static bool All(this IQueryable source, string predicate, params object?[] args) { return All(source, ParsingConfig.Default, predicate, args); } @@ -122,7 +124,7 @@ public static bool All(this IQueryable source, string predicate, params object?[ /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. [PublicAPI] - public static bool All(this IQueryable source, ParsingConfig config, string predicate, params object?[]? args) + public static bool All(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { Check.NotNull(source); Check.NotNull(config); @@ -149,11 +151,9 @@ public static bool All(this IQueryable source, ParsingConfig config, string pred /// /// /// true if the source sequence contains any elements; otherwise, false. - public static bool Any([NotNull] this IQueryable source) + public static bool Any(this IQueryable source) { - Check.NotNull(source, nameof(source)); - - return Execute(_any, source); + return Execute(_any, Check.NotNull(source)); } private static readonly MethodInfo _anyPredicate = QueryableMethodFinder.GetMethod(nameof(Queryable.Any), 1); @@ -175,11 +175,11 @@ public static bool Any([NotNull] this IQueryable source) /// /// true if the source sequence contains any elements; otherwise, false. [PublicAPI] - public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static bool Any(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -188,7 +188,7 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] ParsingConfig } /// - public static bool Any([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static bool Any(this IQueryable source, string predicate, params object?[] args) { return Any(source, ParsingConfig.Default, predicate, args); } @@ -199,10 +199,10 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] string predic /// A sequence to check for being empty. /// A cached Lambda Expression. /// true if the source sequence contains any elements; otherwise, false. - public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static bool Any(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_anyPredicate, source, lambda); } @@ -222,9 +222,9 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpress /// /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source) + public static double Average(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var average = QueryableMethodFinder.GetMethod(nameof(Queryable.Average), source.ElementType, typeof(double)); return Execute(average, source); @@ -245,11 +245,11 @@ public static double Average([NotNull] this IQueryable source) /// /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static double Average(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -259,7 +259,7 @@ public static double Average([NotNull] this IQueryable source, [NotNull] Parsing /// [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static double Average(this IQueryable source, string predicate, params object?[] args) { return Average(source, ParsingConfig.Default, predicate, args); } @@ -271,10 +271,10 @@ public static double Average([NotNull] this IQueryable source, [NotNull] string /// A Lambda Expression. /// The average of the values in the sequence. [PublicAPI] - public static double Average([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static double Average(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var averageSelector = QueryableMethodFinder.GetMethod(nameof(Queryable.Average), lambda.GetReturnType(), typeof(double), 1); return Execute(averageSelector, source, lambda); @@ -288,14 +288,14 @@ public static double Average([NotNull] this IQueryable source, [NotNull] LambdaE /// /// The sequence to type as of . /// The input typed as of . - public static IEnumerable AsEnumerable([NotNull] this IQueryable source) + public static IEnumerable AsEnumerable(this IQueryable source) #else /// /// Returns the input typed as of dynamic. /// /// The sequence to type as of dynamic. /// The input typed as of dynamic. - public static IEnumerable AsEnumerable([NotNull] this IQueryable source) + public static IEnumerable AsEnumerable(this IQueryable source) #endif { foreach (var obj in source) @@ -314,12 +314,12 @@ public static IEnumerable AsEnumerable([NotNull] this IQueryable source /// The that contains the elements to be converted. /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type type) + public static IQueryable Cast(this IQueryable source, Type type) { - Check.NotNull(source, nameof(source)); - Check.NotNull(type, nameof(type)); + Check.NotNull(source); + Check.NotNull(type); - var optimized = OptimizeExpression(Expression.Call(null, _cast.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression })); + var optimized = OptimizeExpression(Expression.Call(null, _cast.MakeGenericMethod(new[] { type }), new[] { source.Expression })); return source.Provider.CreateQuery(optimized); } @@ -331,14 +331,14 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Type t /// The . /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string typeName) + public static IQueryable Cast(this IQueryable source, ParsingConfig config, string typeName) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(typeName, nameof(typeName)); var finder = new TypeFinder(config, new KeywordsHelper(config)); - Type type = finder.FindTypeByName(typeName, null, true); + Type type = finder.FindTypeByName(typeName, null, true)!; return Cast(source, type); } @@ -349,7 +349,7 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] Parsin /// The that contains the elements to be converted. /// The type to convert the elements of source to. /// An that contains each element of the source sequence converted to the specified type. - public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string typeName) + public static IQueryable Cast(this IQueryable source, string typeName) { return Cast(source, ParsingConfig.Default, typeName); } @@ -369,9 +369,9 @@ public static IQueryable Cast([NotNull] this IQueryable source, [NotNull] string /// /// /// The number of elements in the input sequence. - public static int Count([NotNull] this IQueryable source) + public static int Count(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_count, source); } @@ -395,11 +395,11 @@ public static int Count([NotNull] this IQueryable source) /// /// The number of elements in the specified sequence that satisfies a condition. [PublicAPI] - public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static int Count(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -408,7 +408,7 @@ public static int Count([NotNull] this IQueryable source, [NotNull] ParsingConfi } /// - public static int Count([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static int Count(this IQueryable source, string predicate, params object?[] args) { return Count(source, ParsingConfig.Default, predicate, args); } @@ -419,10 +419,10 @@ public static int Count([NotNull] this IQueryable source, [NotNull] string predi /// The that contains the elements to be counted. /// A cached Lambda Expression. /// The number of elements in the specified sequence that satisfies a condition. - public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static int Count(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_countPredicate, source, lambda); } @@ -442,9 +442,9 @@ public static int Count([NotNull] this IQueryable source, [NotNull] LambdaExpres /// /// /// An that contains default if source is empty; otherwise, source. - public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source) + public static IQueryable DefaultIfEmpty(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_defaultIfEmpty, source); } @@ -460,9 +460,9 @@ public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source) /// /// /// An that contains defaultValue if source is empty; otherwise, source. - public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBeNull] object defaultValue) + public static IQueryable DefaultIfEmpty(this IQueryable source, object? defaultValue) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_defaultIfEmptyWithParam, source, Expression.Constant(defaultValue)); } @@ -483,9 +483,9 @@ public static IQueryable DefaultIfEmpty([NotNull] this IQueryable source, [CanBe /// /// /// An that contains distinct elements from the source sequence. - public static IQueryable Distinct([NotNull] this IQueryable source) + public static IQueryable Distinct(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return CreateQuery(_distinct, source); } @@ -500,12 +500,12 @@ public static IQueryable Distinct([NotNull] this IQueryable source) /// The to return the first element of. /// The first element in source. #if NET35 - public static object First([NotNull] this IQueryable source) + public static object First(this IQueryable source) #else - public static dynamic First([NotNull] this IQueryable source) + public static dynamic First(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_first, source); } @@ -522,14 +522,14 @@ public static dynamic First([NotNull] this IQueryable source) /// The first element in source that passes the test in predicate. [PublicAPI] #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object First(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic First(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -539,9 +539,9 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] ParsingC /// #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object First(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic First(this IQueryable source, string predicate, params object?[] args) #endif { return First(source, ParsingConfig.Default, predicate, args); @@ -554,12 +554,12 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] string p /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object First(this IQueryable source, LambdaExpression lambda) #else - public static dynamic First([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic First(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstPredicate, source, lambda); } #endregion First @@ -574,12 +574,12 @@ public static dynamic First([NotNull] this IQueryable source, [NotNull] LambdaEx /// The to return the first element of. /// default if source is empty; otherwise, the first element in source. #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source) + public static object FirstOrDefault(this IQueryable source) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source) + public static dynamic FirstOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstOrDefault, source); } @@ -594,14 +594,14 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source) /// default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. [PublicAPI] #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic FirstOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -611,9 +611,9 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object FirstOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic FirstOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return FirstOrDefault(source, ParsingConfig.Default, predicate, args); @@ -626,12 +626,12 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// A cached Lambda Expression. /// default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate. #if NET35 - public static object FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object FirstOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic FirstOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_firstOrDefaultPredicate, source, lambda); } @@ -655,7 +655,7 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [NotNull] /// /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, object[] args) { return InternalGroupBy(source, config, keySelector, resultSelector, null, args); } @@ -671,23 +671,23 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] Par /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer? equalityComparer, object[]? args) { return InternalGroupBy(source, config, keySelector, resultSelector, equalityComparer, args); } - internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + internal static IQueryable InternalGroupBy(IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer? equalityComparer, object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(keySelector, nameof(keySelector)); Check.NotEmpty(resultSelector, nameof(resultSelector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args); LambdaExpression elementLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, resultSelector, args); - Expression optimized = null; + Expression? optimized; if (equalityComparer == null) { optimized = OptimizeExpression(Expression.Call( @@ -710,13 +710,13 @@ internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, object[] args) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, args); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer, object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer, object[] args) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, equalityComparer, args); } @@ -736,13 +736,13 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// var groupResult2 = queryable.GroupBy("new (NumberPropertyAsKey, StringPropertyAsKey)", "new (StringProperty1, StringProperty2)"); /// /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector) { return GroupBy(source, config, keySelector, resultSelector, null, null); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector); } @@ -757,13 +757,13 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// A string expression to specify a result value from each group. /// The comparer to use. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, string resultSelector, IEqualityComparer equalityComparer) { return InternalGroupBy(source, config, keySelector, resultSelector, equalityComparer, null); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [NotNull] string resultSelector, IEqualityComparer equalityComparer) + public static IQueryable GroupBy(this IQueryable source, string keySelector, string resultSelector, IEqualityComparer equalityComparer) { return GroupBy(source, ParsingConfig.Default, keySelector, resultSelector, equalityComparer); } @@ -784,7 +784,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, params object[]? args) { return InternalGroupBy(source, config, keySelector, null, args); } @@ -799,22 +799,21 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] Par /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The comparer to use. /// A where each element represents a projection over a group and its key. - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer equalityComparer, params object[]? args) { return InternalGroupBy(source, config, keySelector, equalityComparer, args); } - internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + internal static IQueryable InternalGroupBy(IQueryable source, ParsingConfig config, string keySelector, IEqualityComparer? equalityComparer, params object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(keySelector, nameof(keySelector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args); - Expression? optimized = null; - + Expression? optimized; if (equalityComparer == null) { optimized = OptimizeExpression(Expression.Call( @@ -835,13 +834,13 @@ internal static IQueryable InternalGroupBy([NotNull] IQueryable source, [NotNull /// [PublicAPI] - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, params object[]? args) { return GroupBy(source, ParsingConfig.Default, keySelector, args); } /// - public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] string keySelector, IEqualityComparer equalityComparer, [CanBeNull] params object[] args) + public static IQueryable GroupBy(this IQueryable source, string keySelector, IEqualityComparer equalityComparer, params object[]? args) { return GroupBy(source, ParsingConfig.Default, keySelector, equalityComparer, args); } @@ -858,11 +857,11 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [NotNull] str /// The . /// expressions to specify the keys for each element. /// A of type where each element represents a projection over a group, its key, and its subgroups. - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, [NotNull] ParsingConfig config, params string[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, ParsingConfig config, params string[] keySelectors) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.HasNoNulls(keySelectors, nameof(keySelectors)); + Check.NotNull(source); + Check.NotNull(config); + Check.HasNoNulls(keySelectors); var selectors = new List>(keySelectors.Length); @@ -877,7 +876,7 @@ public static IEnumerable GroupByMany([NotNull] this IEnu } /// - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params string[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, params string[] keySelectors) { return GroupByMany(source, ParsingConfig.Default, keySelectors); } @@ -890,10 +889,10 @@ public static IEnumerable GroupByMany([NotNull] this IEnu /// A whose elements to group. /// Lambda expressions to specify the keys for each element. /// A of type where each element represents a projection over a group, its key, and its subgroups. - public static IEnumerable GroupByMany([NotNull] this IEnumerable source, params Func[] keySelectors) + public static IEnumerable GroupByMany(this IEnumerable source, params Func[] keySelectors) { - Check.NotNull(source, nameof(source)); - Check.HasNoNulls(keySelectors, nameof(keySelectors)); + Check.NotNull(source); + Check.HasNoNulls(keySelectors); return GroupByManyInternal(source, keySelectors, 0); } @@ -902,7 +901,7 @@ private static IEnumerable GroupByManyInternal(IEnumerabl { if (currentSelector >= keySelectors.Length) { - return null; + return null!; // TODO } var selector = keySelectors[currentSelector]; @@ -932,10 +931,10 @@ private static IEnumerable GroupByManyInternal(IEnumerabl /// A dynamic function to create a result element from an element from the first sequence and a collection of matching elements from the second sequence. /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// An obtained by performing a grouped join on two sequences. - public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable GroupJoin(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { Check.NotNull(outer, nameof(outer)); - Check.NotNull(config, nameof(config)); + Check.NotNull(config); Check.NotNull(inner, nameof(inner)); Check.NotEmpty(outerKeySelector, nameof(outerKeySelector)); Check.NotEmpty(innerKeySelector, nameof(innerKeySelector)); @@ -944,7 +943,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] Pa Type outerType = outer.ElementType; Type innerType = inner.AsQueryable().ElementType; - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, outer); LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); @@ -969,7 +968,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] Pa } /// - public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return GroupJoin(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -987,12 +986,12 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [NotNull] IE /// A dynamic function to create a result element from two matching elements. /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// An obtained by performing an inner join on two sequences. - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { //http://stackoverflow.com/questions/389094/how-to-create-a-dynamic-linq-join-extension-method Check.NotNull(outer, nameof(outer)); - Check.NotNull(config, nameof(config)); + Check.NotNull(config); Check.NotNull(inner, nameof(inner)); Check.NotEmpty(outerKeySelector, nameof(outerKeySelector)); Check.NotEmpty(innerKeySelector, nameof(innerKeySelector)); @@ -1001,7 +1000,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] Parsing Type outerType = outer.ElementType; Type innerType = inner.AsQueryable().ElementType; - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, outer); LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args); LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args); @@ -1029,7 +1028,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] Parsing } /// - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, [NotNull] string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return Join(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -1047,13 +1046,13 @@ public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumer /// An object array that contains zero or more objects to insert into the predicates as parameters. Similar to the way String.Format formats strings. /// This overload only works on elements where both sequences and the resulting element match. /// An that has elements of type TResult obtained by performing an inner join on two sequences. - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] ParsingConfig config, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, ParsingConfig config, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return (IQueryable)Join(outer, config, (IEnumerable)inner, outerKeySelector, innerKeySelector, resultSelector, args); } /// - public static IQueryable Join([NotNull] this IQueryable outer, [NotNull] IEnumerable inner, [NotNull] string outerKeySelector, [NotNull] string innerKeySelector, string resultSelector, params object[] args) + public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerKeySelector, string innerKeySelector, string resultSelector, params object?[] args) { return Join(outer, ParsingConfig.Default, inner, outerKeySelector, innerKeySelector, resultSelector, args); } @@ -1069,12 +1068,12 @@ public static IQueryable Join([NotNull] this IQueryableThe to return the last element of. /// The last element in source. #if NET35 - public static object Last([NotNull] this IQueryable source) + public static object Last(this IQueryable source) #else - public static dynamic Last([NotNull] this IQueryable source) + public static dynamic Last(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_last, source); } @@ -1088,14 +1087,14 @@ public static dynamic Last([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Last(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic Last(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1105,9 +1104,9 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] ParsingCo /// #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object Last(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic Last(this IQueryable source, string predicate, params object?[] args) #endif { return Last(source, ParsingConfig.Default, predicate, args); @@ -1121,12 +1120,12 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] string pr /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Last(this IQueryable source, LambdaExpression lambda) #else - public static dynamic Last([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic Last(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastPredicate, source, lambda); } #endregion Last @@ -1141,12 +1140,12 @@ public static dynamic Last([NotNull] this IQueryable source, [NotNull] LambdaExp /// The to return the last element of. /// default if source is empty; otherwise, the last element in source. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source) + public static object LastOrDefault(this IQueryable source) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source) + public static dynamic LastOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastDefault, source); } @@ -1160,14 +1159,14 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic LastOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1177,9 +1176,9 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object LastOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic LastOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return LastOrDefault(source, ParsingConfig.Default, predicate, args); @@ -1192,12 +1191,12 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object LastOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic LastOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_lastDefaultPredicate, source, lambda); } #endregion LastOrDefault @@ -1217,9 +1216,9 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [NotNull] /// /// /// The number of elements in the input sequence. - public static long LongCount([NotNull] this IQueryable source) + public static long LongCount(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_longCount, source); } @@ -1241,11 +1240,11 @@ public static long LongCount([NotNull] this IQueryable source) /// /// The number of elements in the specified sequence that satisfies a condition. [PublicAPI] - public static long LongCount([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static long LongCount(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -1254,7 +1253,7 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] Parsing } /// - public static long LongCount([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static long LongCount(this IQueryable source, string predicate, params object?[] args) { return LongCount(source, ParsingConfig.Default, predicate, args); } @@ -1265,10 +1264,10 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] string /// The that contains the elements to be counted. /// A cached Lambda Expression. /// The number of elements in the specified sequence that satisfies a condition. - public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static long LongCount(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_longCountPredicate, source, lambda); } @@ -1291,9 +1290,9 @@ public static long LongCount([NotNull] this IQueryable source, [NotNull] LambdaE /// /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source) + public static object Max(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_max, source); } @@ -1313,11 +1312,11 @@ public static object Max([NotNull] this IQueryable source) /// /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Max(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); @@ -1327,7 +1326,7 @@ public static object Max([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Max(this IQueryable source, string predicate, params object?[] args) { return Max(source, ParsingConfig.Default, predicate, args); } @@ -1339,9 +1338,9 @@ public static object Max([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The max element in the sequence. [PublicAPI] - public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Max(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_maxPredicate, source, lambda); } #endregion Max @@ -1363,9 +1362,9 @@ public static object Max([NotNull] this IQueryable source, [NotNull] LambdaExpre /// /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source) + public static object Min(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_min, source); } @@ -1385,11 +1384,11 @@ public static object Min([NotNull] this IQueryable source) /// /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Min(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(object), predicate, args); @@ -1399,7 +1398,7 @@ public static object Min([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Min(this IQueryable source, string predicate, params object?[] args) { return Min(source, ParsingConfig.Default, predicate, args); } @@ -1411,9 +1410,9 @@ public static object Min([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The min element in the sequence. [PublicAPI] - public static object Min([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Min(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_minPredicate, source, lambda); } #endregion Min @@ -1487,13 +1486,13 @@ public static IQueryable OfType(this IQueryable source, string typeName) /// ]]> /// /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object?[] args) { return (IOrderedQueryable)OrderBy((IQueryable)source, config, ordering, args); } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, args); } @@ -1508,9 +1507,9 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { - return (IOrderedQueryable)InternalOrderBy((IQueryable)source, config, ordering, comparer, args); + return (IOrderedQueryable)InternalOrderBy(source, config, ordering, comparer, args); } /// @@ -1522,7 +1521,7 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -1542,11 +1541,11 @@ public static IOrderedQueryable OrderBy([NotNull] this IQuerya /// var resultMultiple = queryable.OrderBy("NumberProperty, StringProperty DESC"); /// /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object?[] args) { - if (args.Length > 0 && args[0] != null && args[0].GetType().GetInterfaces().Any(i => i.Name.Contains("IComparer`1"))) + if (args.Length > 0 && args[0] != null && args[0]!.GetType().GetInterfaces().Any(i => i.Name.Contains("IComparer`1"))) { - return InternalOrderBy(source, ParsingConfig.Default, ordering, args[0], args); + return InternalOrderBy(source, ParsingConfig.Default, ordering, args[0]!, args); } return InternalOrderBy(source, config, ordering, null, args); @@ -1561,15 +1560,15 @@ public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNu /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { return InternalOrderBy(source, config, ordering, comparer, args); } - internal static IOrderedQueryable InternalOrderBy([NotNull] IQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, object comparer, params object[] args) + internal static IOrderedQueryable InternalOrderBy(IQueryable source, ParsingConfig config, string ordering, object? comparer, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(ordering, nameof(ordering)); ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty, config.RenameEmptyParameterExpressionNames) }; @@ -1619,13 +1618,13 @@ internal static IOrderedQueryable InternalOrderBy([NotNull] IQueryable source, [ } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, args); } /// - public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable OrderBy(this IQueryable source, string ordering, IComparer comparer, params object?[] args) { return OrderBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -1640,9 +1639,9 @@ public static IOrderedQueryable OrderBy([NotNull] this IQueryable source, [NotNu /// The page to return. /// The number of elements per page. /// A that contains the paged elements. - public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) + public static IQueryable Page(this IQueryable source, int page, int pageSize) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); @@ -1657,9 +1656,9 @@ public static IQueryable Page([NotNull] this IQueryable source, int page, int pa /// The page to return. /// The number of elements per page. /// A that contains the paged elements. - public static IQueryable Page([NotNull] this IQueryable source, int page, int pageSize) + public static IQueryable Page(this IQueryable source, int page, int pageSize) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); @@ -1674,9 +1673,9 @@ public static IQueryable Page([NotNull] this IQueryableThe number of elements per page. /// If this optional parameter has been defined, this value is used as the RowCount instead of executing a Linq `Count()`. /// PagedResult - public static PagedResult PageResult([NotNull] this IQueryable source, int page, int pageSize, int? rowCount = null) + public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); Check.Condition(rowCount, rc => rc == null || rc >= 0, nameof(rowCount)); @@ -1705,7 +1704,7 @@ public static PagedResult PageResult([NotNull] this IQueryable source, int page, /// PagedResult{TSource} public static PagedResult PageResult(this IQueryable source, int page, int pageSize, int? rowCount = null) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(page, p => p > 0, nameof(page)); Check.Condition(pageSize, ps => ps > 0, nameof(pageSize)); Check.Condition(rowCount, rc => rc == null || rc >= 0, nameof(rowCount)); @@ -1730,9 +1729,9 @@ public static PagedResult PageResult(this IQueryable /// /// A sequence of values to reverse. /// A whose elements correspond to those of the input sequence in reverse order. - public static IQueryable Reverse([NotNull] this IQueryable source) + public static IQueryable Reverse(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Queryable.Reverse((IQueryable)source); } @@ -1753,13 +1752,13 @@ public static IQueryable Reverse([NotNull] this IQueryable source) /// var dynamicObject = queryable.Select("new (StringProperty1, StringProperty2 as OtherStringPropertyName)"); /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1772,7 +1771,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Pars } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, selector, args); } @@ -1794,13 +1793,13 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] stri /// ]]> /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(TResult), selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1812,7 +1811,7 @@ public static IQueryable Select([NotNull] this IQueryable sour } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, selector, args); } @@ -1832,14 +1831,14 @@ public static IQueryable Select([NotNull] this IQueryable sour /// var users = queryable.Select(typeof(User), "new (Username, Pwd as Password)"); /// /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(resultType, nameof(resultType)); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, resultType, selector, args); var optimized = OptimizeExpression(Expression.Call( @@ -1851,7 +1850,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Pars } /// - public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable Select(this IQueryable source, Type resultType, string selector, params object?[] args) { return Select(source, ParsingConfig.Default, resultType, selector, args); } @@ -1872,13 +1871,13 @@ public static IQueryable Select([NotNull] this IQueryable source, [NotNull] Type /// var roles = users.SelectMany("Roles"); /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { return SelectManyInternal(source, config, null, selector, args); } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, selector, args); } @@ -1897,10 +1896,10 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// var permissions = users.SelectMany(typeof(Permission), "Roles.SelectMany(Permissions)"); /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, Type resultType, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(resultType, nameof(resultType)); Check.NotEmpty(selector, nameof(selector)); @@ -1908,14 +1907,14 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] Type resultType, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, Type resultType, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, resultType, selector, args); } - private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args) + private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig config, Type? resultType, string selector, params object?[] args) { - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args); //Extra help to get SelectMany to work from StackOverflow Answer @@ -1969,13 +1968,13 @@ private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig co /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string selector, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(selector, nameof(selector)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(createParameterCtor, source.ElementType, null, selector, args); //we have to adjust to lambda to return an IEnumerable instead of whatever the actual property is. @@ -1994,7 +1993,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string selector, params object[] args) + public static IQueryable SelectMany(this IQueryable source, string selector, params object?[] args) { return SelectMany(source, ParsingConfig.Default, selector, args); } @@ -2023,13 +2022,13 @@ public static IQueryable SelectMany([NotNull] this IQueryable /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, ParsingConfig config, string collectionSelector, string resultSelector, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, collectionSelector, resultSelector, "x", "y", collectionSelectorArgs, resultSelectorArgs); } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, ParsingConfig.Default, collectionSelector, resultSelector, "x", "y", collectionSelectorArgs, resultSelectorArgs); } @@ -2060,16 +2059,24 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// ]]> /// /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany( + this IQueryable source, + ParsingConfig config, + string collectionSelector, + string resultSelector, + string collectionParameterName, + string resultParameterName, + object?[]? collectionSelectorArgs = null, + params object[]? resultSelectorArgs) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(collectionSelector, nameof(collectionSelector)); Check.NotEmpty(collectionParameterName, nameof(collectionParameterName)); Check.NotEmpty(resultSelector, nameof(resultSelector)); Check.NotEmpty(resultParameterName, nameof(resultParameterName)); - bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source); + bool createParameterCtor = config.EvaluateGroupByAtDatabase || SupportsLinqToObjects(config, source); LambdaExpression sourceSelectLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, collectionSelector, collectionSelectorArgs); //we have to adjust to lambda to return an IEnumerable instead of whatever the actual property is. @@ -2097,7 +2104,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] } /// - public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] string collectionSelector, [NotNull] string resultSelector, [NotNull] string collectionParameterName, [NotNull] string resultParameterName, [CanBeNull] object[] collectionSelectorArgs = null, [CanBeNull] params object[] resultSelectorArgs) + public static IQueryable SelectMany(this IQueryable source, string collectionSelector, string resultSelector, string collectionParameterName, string resultParameterName, object[]? collectionSelectorArgs = null, params object[]? resultSelectorArgs) { return SelectMany(source, ParsingConfig.Default, collectionSelector, resultSelector, collectionParameterName, resultParameterName, collectionSelectorArgs, resultSelectorArgs); } @@ -2115,12 +2122,12 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull] /// A to return the single element of. /// The single element of the input sequence. #if NET35 - public static object Single([NotNull] this IQueryable source) + public static object Single(this IQueryable source) #else - public static dynamic Single([NotNull] this IQueryable source) + public static dynamic Single(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.Single), new[] { source.ElementType }, source.Expression)); return source.Provider.Execute(optimized); @@ -2136,14 +2143,14 @@ public static dynamic Single([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Single(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic Single(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2153,9 +2160,9 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] Parsing /// #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object Single(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic Single(this IQueryable source, string predicate, params object?[] args) #endif { return Single(source, ParsingConfig.Default, predicate, args); @@ -2169,12 +2176,12 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] string /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Single(this IQueryable source, LambdaExpression lambda) #else - public static dynamic Single([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic Single(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); return Execute(_singlePredicate, source, lambda); } @@ -2186,15 +2193,15 @@ public static dynamic Single([NotNull] this IQueryable source, [NotNull] LambdaE /// A to return the single element of. /// The single element of the input sequence, or default if the sequence contains no elements. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source) + public static object SingleOrDefault(this IQueryable source) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source) + public static dynamic SingleOrDefault(this IQueryable source) #endif { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.SingleOrDefault), new[] { source.ElementType }, source.Expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } /// @@ -2207,14 +2214,14 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source) /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// The first element in source that passes the test in predicate. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static dynamic SingleOrDefault(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2224,9 +2231,9 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static object SingleOrDefault(this IQueryable source, string predicate, params object?[] args) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static dynamic SingleOrDefault(this IQueryable source, string predicate, params object?[] args) #endif { return SingleOrDefault(source, ParsingConfig.Default, predicate, args); @@ -2240,13 +2247,13 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// A cached Lambda Expression. /// The first element in source that passes the test in predicate. #if NET35 - public static object SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object SingleOrDefault(this IQueryable source, LambdaExpression lambda) #else - public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static dynamic SingleOrDefault(this IQueryable source, LambdaExpression lambda) #endif { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); return Execute(_singleDefaultPredicate, source, lambda); } @@ -2261,9 +2268,9 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [NotNull /// A to return elements from. /// The number of elements to skip before returning the remaining elements. /// A that contains elements that occur after the specified index in the input sequence. - public static IQueryable Skip([NotNull] this IQueryable source, int count) + public static IQueryable Skip(this IQueryable source, int count) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(count, x => x >= 0, nameof(count)); //no need to skip if count is zero @@ -2292,10 +2299,10 @@ public static IQueryable Skip([NotNull] this IQueryable source, int count) /// /// /// An that contains elements from source starting at the first element in the linear series that does not pass the test specified by predicate. - public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable SkipWhile(this IQueryable source, ParsingConfig config, string predicate, params object[]? args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(predicate, nameof(predicate)); bool createParameterCtor = SupportsLinqToObjects(config, source); @@ -2305,7 +2312,7 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] P } /// - public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable SkipWhile(this IQueryable source, string predicate, params object[]? args) { return SkipWhile(source, ParsingConfig.Default, predicate, args); } @@ -2325,9 +2332,9 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] s /// /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source) + public static object Sum(this IQueryable source) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); var sum = QueryableMethodFinder.GetMethod(nameof(Queryable.Sum), source.ElementType); return Execute(sum, source); @@ -2348,11 +2355,11 @@ public static object Sum([NotNull] this IQueryable source) /// /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static object Sum(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2364,7 +2371,7 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] ParsingConf /// [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static object Sum(this IQueryable source, string predicate, params object?[] args) { return Sum(source, ParsingConfig.Default, predicate, args); } @@ -2376,10 +2383,10 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] string pred /// A Lambda Expression. /// The sum of the values in the sequence. [PublicAPI] - public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static object Sum(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var sumSelector = QueryableMethodFinder.GetMethod(nameof(Queryable.Sum), lambda.GetReturnType(), 1); @@ -2395,9 +2402,9 @@ public static object Sum([NotNull] this IQueryable source, [NotNull] LambdaExpre /// The sequence to return elements from. /// The number of elements to return. /// A that contains the specified number of elements from the start of source. - public static IQueryable Take([NotNull] this IQueryable source, int count) + public static IQueryable Take(this IQueryable source, int count) { - Check.NotNull(source, nameof(source)); + Check.NotNull(source); Check.Condition(count, x => x >= 0, nameof(count)); return CreateQuery(_take, source, Expression.Constant(count)); @@ -2422,10 +2429,10 @@ public static IQueryable Take([NotNull] this IQueryable source, int count) /// /// /// An that contains elements from the input sequence occurring before the element at which the test specified by predicate no longer passes. - public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable TakeWhile(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotNull(predicate, nameof(predicate)); bool createParameterCtor = SupportsLinqToObjects(config, source); @@ -2435,7 +2442,7 @@ public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] P } /// - public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] string predicate, [CanBeNull] params object[] args) + public static IQueryable TakeWhile(this IQueryable source, string predicate, params object?[] args) { return TakeWhile(source, ParsingConfig.Default, predicate, args); } @@ -2462,13 +2469,13 @@ public static IQueryable TakeWhile([NotNull] this IQueryable source, [NotNull] s /// ]]> /// /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object?[] args) { return (IOrderedQueryable)ThenBy((IOrderedQueryable)source, config, ordering, args); } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, args); } @@ -2483,9 +2490,9 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { - return (IOrderedQueryable)InternalThenBy((IOrderedQueryable)source, config, ordering, comparer, args); + return (IOrderedQueryable)InternalThenBy(source, config, ordering, comparer, args); } /// @@ -2497,7 +2504,7 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -2518,7 +2525,7 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrdered /// var resultMultiple = result.OrderBy("NumberProperty, StringProperty DESC"); /// /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, params object?[] args) { return InternalThenBy(source, config, ordering, null, args); } @@ -2532,15 +2539,15 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, /// The comparer to use. /// An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings. /// A whose elements are sorted according to the specified . - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, ParsingConfig config, string ordering, IComparer comparer, params object?[] args) { return InternalThenBy(source, config, ordering, comparer, args); } - internal static IOrderedQueryable InternalThenBy([NotNull] IOrderedQueryable source, [NotNull] ParsingConfig config, [NotNull] string ordering, IComparer comparer, params object[] args) + internal static IOrderedQueryable InternalThenBy(IOrderedQueryable source, ParsingConfig config, string ordering, IComparer? comparer, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); + Check.NotNull(source); + Check.NotNull(config); Check.NotEmpty(ordering, nameof(ordering)); ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty, config.RenameEmptyParameterExpressionNames) }; @@ -2574,13 +2581,13 @@ internal static IOrderedQueryable InternalThenBy([NotNull] IOrderedQueryable sou } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, args); } /// - public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, [NotNull] string ordering, IComparer comparer, params object[] args) + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string ordering, IComparer comparer, params object?[] args) { return ThenBy(source, ParsingConfig.Default, ordering, comparer, args); } @@ -2606,13 +2613,13 @@ public static IOrderedQueryable ThenBy([NotNull] this IOrderedQueryable source, /// var result5 = queryable.Where("StringProperty = @0", "abc"); /// /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { return (IQueryable)Where((IQueryable)source, config, predicate, args); } - /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + /// + public static IQueryable Where(this IQueryable source, string predicate, params object?[] args) { return Where(source, ParsingConfig.Default, predicate, args); } @@ -2634,11 +2641,11 @@ public static IQueryable Where([NotNull] this IQueryable /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] ParsingConfig config, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, ParsingConfig config, string predicate, params object?[] args) { - Check.NotNull(source, nameof(source)); - Check.NotNull(config, nameof(config)); - Check.NotEmpty(predicate, nameof(predicate)); + Check.NotNull(source); + Check.NotNull(config); + Check.NotEmpty(predicate); bool createParameterCtor = SupportsLinqToObjects(config, source); LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args); @@ -2648,7 +2655,7 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] Parsi } /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] string predicate, params object[] args) + public static IQueryable Where(this IQueryable source, string predicate, params object?[] args) { return Where(source, ParsingConfig.Default, predicate, args); } @@ -2659,17 +2666,17 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] strin /// A to filter. /// A cached Lambda Expression. /// A that contains elements from the input sequence that satisfy the condition specified by LambdaExpression. - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static IQueryable Where(this IQueryable source, LambdaExpression lambda) { - Check.NotNull(source, nameof(source)); - Check.NotNull(lambda, nameof(lambda)); + Check.NotNull(source); + Check.NotNull(lambda); var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[] { source.ElementType }, source.Expression, Expression.Quote(lambda))); return source.Provider.CreateQuery(optimized); } /// - public static IQueryable Where([NotNull] this IQueryable source, [NotNull] LambdaExpression lambda) + public static IQueryable Where(this IQueryable source, LambdaExpression lambda) { return (IQueryable)Where((IQueryable)source, lambda); } @@ -2681,7 +2688,7 @@ private static bool SupportsLinqToObjects(ParsingConfig config, IQueryable query return config.QueryableAnalyzer.SupportsLinqToObjects(query); } - private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object[] args) + private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object?[] args) { Type outerSelectorReturnType = outerSelectorLambda.Body.Type; Type innerSelectorReturnType = innerSelectorLambda.Body.Type; @@ -2740,7 +2747,7 @@ private static object Execute(MethodInfo operatorMethodInfo, IQueryable source) } var optimized = OptimizeExpression(Expression.Call(null, operatorMethodInfo, source.Expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } private static TResult Execute(MethodInfo operatorMethodInfo, IQueryable source) @@ -2765,7 +2772,7 @@ private static object Execute(MethodInfo operatorMethodInfo, IQueryable source, : operatorMethodInfo.MakeGenericMethod(source.ElementType); var optimized = OptimizeExpression(Expression.Call(null, operatorMethodInfo, source.Expression, expression)); - return source.Provider.Execute(optimized); + return source.Provider.Execute(optimized)!; } private static TResult Execute(MethodInfo operatorMethodInfo, IQueryable source, LambdaExpression expression) @@ -2786,4 +2793,4 @@ private static TResult Execute(MethodInfo operatorMethodInfo, IQueryabl #endregion Private Helpers } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/GroupResult.cs b/src/System.Linq.Dynamic.Core/GroupResult.cs index bd8aa556..591911da 100644 --- a/src/System.Linq.Dynamic.Core/GroupResult.cs +++ b/src/System.Linq.Dynamic.Core/GroupResult.cs @@ -13,9 +13,9 @@ public class GroupResult /// The key value of the group. /// #if NET35 || SILVERLIGHT - public object Key { get; internal set; } + public object Key { get; internal set; } = null!; #else - public dynamic Key { get; internal set; } + public dynamic Key { get; internal set; } = null!; #endif /// @@ -31,7 +31,7 @@ public class GroupResult /// /// The resulting subgroups in the group. /// - public IEnumerable Subgroups { get; internal set; } + public IEnumerable? Subgroups { get; internal set; } /// /// Returns a showing the key of the group and the number of items in the group. diff --git a/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs b/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs index 530abf1b..163f5121 100644 --- a/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs +++ b/src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs @@ -1,18 +1,15 @@ -using JetBrains.Annotations; +namespace System.Linq.Dynamic.Core; -namespace System.Linq.Dynamic.Core +/// +/// Interface for QueryableAnalyzer. +/// +public interface IQueryableAnalyzer { /// - /// Interface for QueryableAnalyzer. + /// Determines whether the specified query (and provider) supports LinqToObjects. /// - public interface IQueryableAnalyzer - { - /// - /// Determines whether the specified query (and provider) supports LinqToObjects. - /// - /// The query to check. - /// The provider to check (can be null). - /// true/false - bool SupportsLinqToObjects([NotNull] IQueryable query, [CanBeNull] IQueryProvider provider = null); - } -} + /// The query to check. + /// The provider to check (can be null). + /// true/false + bool SupportsLinqToObjects(IQueryable query, IQueryProvider? provider = null); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs b/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs index 0c42bd5c..974a0c78 100644 --- a/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/ParameterExpressionHelper.cs @@ -1,57 +1,27 @@ using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core +namespace System.Linq.Dynamic.Core; + +internal static class ParameterExpressionHelper { - internal static class ParameterExpressionHelper + public static ParameterExpression CreateParameterExpression(Type type, string name, bool renameEmpty = false) { - public static ParameterExpression CreateParameterExpression(Type type, string name, bool renameEmpty = false) + string paramName = name; + if (renameEmpty && paramName.IsNullOrWhiteSpace()) { - string paramName = name; - if (renameEmpty && IsNullOrWhiteSpace(paramName)) - { - paramName = GenerateRandomWord(); - } - return Expression.Parameter(type, paramName); + paramName = GenerateRandomWord(); } - /// - /// Indicates whether a specified string is null, empty, or consists only of white-space - /// characters. - /// - /// Recreates the same functionality as System.String.IsNullOrWhiteSpace but included here - /// for compatibility with net35. - /// - /// - /// The string to test. - /// - /// - /// true if the value parameter is null or System.String.Empty, or if value consists - /// exclusively of white-space characters. - /// - internal static bool IsNullOrWhiteSpace(string value) - { - if (value == null) - { - return true; - } - for (int i = 0; i < value.Length; i++) - { - if (!char.IsWhiteSpace(value[i])) - { - return false; - } - } - return true; - } + return Expression.Parameter(type, paramName); + } - /// - /// Generates a random 16 character word derived from a Guid value. - /// - internal static string GenerateRandomWord() - { - const int wordLength = 16; - const int diff = 'A' - '0'; - return string.Concat(Guid.NewGuid().ToString(@"N").Select(c => (char)(c + diff)).Take(wordLength)).ToLower(); - } + /// + /// Generates a random 16 character word derived from a Guid value. + /// + internal static string GenerateRandomWord() + { + const int wordLength = 16; + const int diff = 'A' - '0'; + return string.Concat(Guid.NewGuid().ToString(@"N").Select(c => (char)(c + diff)).Take(wordLength)).ToLower(); } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/Constants.cs b/src/System.Linq.Dynamic.Core/Parser/Constants.cs index 86555261..d28c6a50 100644 --- a/src/System.Linq.Dynamic.Core/Parser/Constants.cs +++ b/src/System.Linq.Dynamic.Core/Parser/Constants.cs @@ -1,12 +1,11 @@ using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Parser +namespace System.Linq.Dynamic.Core.Parser; + +internal static class Constants { - internal static class Constants + public static bool IsNull(Expression exp) { - public static bool IsNull(Expression exp) - { - return exp is ConstantExpression cExp && cExp.Value == null; - } + return exp is ConstantExpression { Value: null }; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs index 5d97093c..2a8dc419 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs @@ -14,9 +14,7 @@ internal class ExpressionHelper : IExpressionHelper internal ExpressionHelper(ParsingConfig parsingConfig) { - Check.NotNull(parsingConfig, nameof(parsingConfig)); - - _parsingConfig = parsingConfig; + _parsingConfig = Check.NotNull(parsingConfig); } public void WrapConstantExpression(ref Expression argument) @@ -186,16 +184,16 @@ public void OptimizeForEqualityIfPossible(ref Expression left, ref Expression ri if (rightType == typeof(string) && right.NodeType == ExpressionType.Constant) { - right = OptimizeStringForEqualityIfPossible((string)((ConstantExpression)right).Value, leftType) ?? right; + right = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)right).Value, leftType) ?? right; } if (leftType == typeof(string) && left.NodeType == ExpressionType.Constant) { - left = OptimizeStringForEqualityIfPossible((string)((ConstantExpression)left).Value, rightType) ?? left; + left = OptimizeStringForEqualityIfPossible((string?)((ConstantExpression)left).Value, rightType) ?? left; } } - public Expression? OptimizeStringForEqualityIfPossible(string text, Type type) + public Expression? OptimizeStringForEqualityIfPossible(string? text, Type type) { if (type == typeof(DateTime) && DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) { @@ -309,7 +307,7 @@ public Expression GenerateDefaultExpression(Type type) #endif } - private Expression? GetMemberExpression(Expression expression) + private Expression? GetMemberExpression(Expression? expression) { if (ExpressionQualifiesForNullPropagation(expression)) { diff --git a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs index 3c65bcad..791e506c 100644 --- a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs @@ -11,11 +11,11 @@ namespace System.Linq.Dynamic.Core.Parser /// public class NumberParser { - private static readonly Regex RegexBinary32 = new Regex("^[01]{1,32}$", RegexOptions.Compiled); - private static readonly Regex RegexBinary64 = new Regex("^[01]{1,64}$", RegexOptions.Compiled); - private static readonly char[] Qualifiers = new[] { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd', 'M', 'm' }; - private static readonly char[] QualifiersHex = new[] { 'U', 'u', 'L', 'l' }; - private static readonly string[] QualifiersReal = new[] { "F", "f", "D", "d", "M", "m" }; + private static readonly Regex RegexBinary32 = new("^[01]{1,32}$", RegexOptions.Compiled); + private static readonly Regex RegexBinary64 = new("^[01]{1,64}$", RegexOptions.Compiled); + private static readonly char[] Qualifiers = { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd', 'M', 'm' }; + private static readonly char[] QualifiersHex = { 'U', 'u', 'L', 'l' }; + private static readonly string[] QualifiersReal = { "F", "f", "D", "d", "M", "m" }; private readonly CultureInfo _culture; diff --git a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs index 5b827fee..c3175069 100644 --- a/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs +++ b/src/System.Linq.Dynamic.Core/Parser/TypeFinder.cs @@ -10,8 +10,8 @@ internal class TypeFinder : ITypeFinder public TypeFinder(ParsingConfig parsingConfig, IKeywordsHelper keywordsHelper) { - Check.NotNull(parsingConfig, nameof(parsingConfig)); - Check.NotNull(keywordsHelper, nameof(keywordsHelper)); + Check.NotNull(parsingConfig); + Check.NotNull(keywordsHelper); _keywordsHelper = keywordsHelper; _parsingConfig = parsingConfig; @@ -19,7 +19,7 @@ public TypeFinder(ParsingConfig parsingConfig, IKeywordsHelper keywordsHelper) public Type? FindTypeByName(string name, ParameterExpression?[]? expressions, bool forceUseCustomTypeProvider) { - Check.NotEmpty(name, nameof(name)); + Check.NotEmpty(name); _keywordsHelper.TryGetValue(name, out var type); diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs index 3bb0e06a..a0b4e954 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/CustomDateTimeConverter.cs @@ -1,23 +1,22 @@ using System.ComponentModel; using System.Globalization; -namespace System.Linq.Dynamic.Core.TypeConverters +namespace System.Linq.Dynamic.Core.TypeConverters; + +internal class CustomDateTimeConverter : DateTimeOffsetConverter { - internal class CustomDateTimeConverter : DateTimeOffsetConverter + /// + /// Converts the specified object to a . + /// + /// The date format context. + /// The date culture. + /// The object to be converted. + /// A that represents the specified object. + /// The conversion cannot be performed. + public override object? ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - /// - /// Converts the specified object to a . - /// - /// The date format context. - /// The date culture. - /// The object to be converted. - /// A that represents the specified object. - /// The conversion cannot be performed. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - var dateTimeOffset = base.ConvertFrom(context, culture, value) as DateTimeOffset?; + var dateTimeOffset = base.ConvertFrom(context, culture, value) as DateTimeOffset?; - return dateTimeOffset?.UtcDateTime; - } + return dateTimeOffset?.UtcDateTime; } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs index afbcb033..ad947160 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/ITypeConverterFactory.cs @@ -1,15 +1,13 @@ -using JetBrains.Annotations; -using System.ComponentModel; +using System.ComponentModel; -namespace System.Linq.Dynamic.Core.TypeConverters +namespace System.Linq.Dynamic.Core.TypeConverters; + +interface ITypeConverterFactory { - interface ITypeConverterFactory - { - /// - /// Returns a type converter for the specified type. - /// - /// The System.Type of the target component. - /// A System.ComponentModel.TypeConverter for the specified type. - TypeConverter GetConverter([NotNull] Type type); - } -} + /// + /// Returns a type converter for the specified type. + /// + /// The System.Type of the target component. + /// A System.ComponentModel.TypeConverter for the specified type. + TypeConverter GetConverter(Type type); +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs index 4a317f9f..d6a4bc92 100644 --- a/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs +++ b/src/System.Linq.Dynamic.Core/TypeConverters/TypeConverterFactory.cs @@ -10,13 +10,13 @@ internal class TypeConverterFactory : ITypeConverterFactory public TypeConverterFactory(ParsingConfig config) { - _config = Check.NotNull(config, nameof(config)); + _config = Check.NotNull(config); } /// public TypeConverter GetConverter(Type type) { - Check.NotNull(type, nameof(type)); + Check.NotNull(type); if (_config.DateTimeIsParsedAsUTC && (type == typeof(DateTime) || type == typeof(DateTime?))) { @@ -47,4 +47,4 @@ public TypeConverter GetConverter(Type type) #endif } } -} +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs b/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs index 960baa12..31b0c558 100644 --- a/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs +++ b/src/System.Linq.Dynamic.Core/Util/ParameterExpressionRenamer.cs @@ -1,74 +1,70 @@ -using JetBrains.Annotations; -using System.Linq.Dynamic.Core.Validation; +using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; -namespace System.Linq.Dynamic.Core.Util +namespace System.Linq.Dynamic.Core.Util; + +/// +/// Renames a single (Typed)ParameterExpression in an Expression. +/// +/// +internal class ParameterExpressionRenamer : ExpressionVisitor { + private readonly string _newName; + private readonly string _oldName; + + private ParameterExpression? _parameterExpression; + /// - /// Renames a single (Typed)ParameterExpression in an Expression. + /// Initializes a new instance of the class. /// - /// - internal class ParameterExpressionRenamer : ExpressionVisitor + /// The new name (the oldName is assumed to be ""). + public ParameterExpressionRenamer(string newName) : this(string.Empty, newName) { - private readonly string _newName; - private readonly string _oldName; - - private ParameterExpression _parameterExpression; - - /// - /// Initializes a new instance of the class. - /// - /// The new name (the oldName is assumed to be ""). - public ParameterExpressionRenamer([NotNull] string newName) : this("", newName) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The old name. - /// The new name. - public ParameterExpressionRenamer([NotNull] string oldName, [NotNull] string newName) - { - Check.NotNull(oldName, nameof(oldName)); - Check.NotEmpty(newName, nameof(newName)); + /// + /// Initializes a new instance of the class. + /// + /// The old name. + /// The new name. + public ParameterExpressionRenamer(string oldName, string newName) + { + Check.NotNull(oldName); + Check.NotEmpty(newName); - _oldName = oldName; - _newName = newName; - } + _oldName = oldName; + _newName = newName; + } - /// - /// Renames a single (Typed)ParameterExpression from specified expression. - /// - /// The expression. - /// The new generated (Typed)ParameterExpression. - /// Renamed Expression - public Expression Rename(Expression expression, out ParameterExpression parameterExpression) - { - var visitedExpression = Visit(expression); + /// + /// Renames a single (Typed)ParameterExpression from specified expression. + /// + /// The expression. + /// The new generated (Typed)ParameterExpression. + /// Renamed Expression + public Expression Rename(Expression expression, out ParameterExpression? parameterExpression) + { + var visitedExpression = Visit(expression); - parameterExpression = _parameterExpression; + parameterExpression = _parameterExpression; - return visitedExpression; - } + return visitedExpression; + } - /// - protected override Expression VisitParameter(ParameterExpression node) + /// + protected override Expression VisitParameter(ParameterExpression node) + { + if (string.Equals(_oldName, node.Name, StringComparison.Ordinal)) { - if (string.Equals(_oldName, node.Name, StringComparison.Ordinal)) - { - if (_parameterExpression == null) - { - _parameterExpression = ParameterExpressionHelper.CreateParameterExpression(node.Type, _newName); - } - - return _parameterExpression; - // throw new InvalidOperationException($"The {nameof(ParameterExpressionRenamer)} can only rename 1 (Typed)ParameterExpression in an Expression."); - } - else + if (_parameterExpression == null) { - return node; + _parameterExpression = ParameterExpressionHelper.CreateParameterExpression(node.Type, _newName); } + + return _parameterExpression; + // throw new InvalidOperationException($"The {nameof(ParameterExpressionRenamer)} can only rename 1 (Typed)ParameterExpression in an Expression."); } + + return node; } } diff --git a/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs b/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs index 69b93247..d304f5a5 100644 --- a/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs +++ b/src/System.Linq.Dynamic.Core/Util/QueryableMethodFinder.cs @@ -1,47 +1,46 @@ using System.Linq.Expressions; using System.Reflection; -namespace System.Linq.Dynamic.Core.Util +namespace System.Linq.Dynamic.Core.Util; + +internal static class QueryableMethodFinder { - internal static class QueryableMethodFinder + public static MethodInfo GetGenericMethod(string name) { - public static MethodInfo GetGenericMethod(string name) - { - return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => mi.IsGenericMethod); - } + return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => mi.IsGenericMethod); + } - public static MethodInfo GetMethod(string name, Type argumentType, Type returnType, int parameterCount = 0, Func predicate = null) => - GetMethod(name, returnType, parameterCount, mi => mi.ToString().Contains(argumentType.ToString()) && ((predicate == null) || predicate(mi))); + public static MethodInfo GetMethod(string name, Type argumentType, Type returnType, int parameterCount = 0, Func? predicate = null) => + GetMethod(name, returnType, parameterCount, mi => mi.ToString().Contains(argumentType.ToString()) && ((predicate == null) || predicate(mi))); - public static MethodInfo GetMethod(string name, Type returnType, int parameterCount = 0, Func predicate = null) => - GetMethod(name, parameterCount, mi => (mi.ReturnType == returnType) && ((predicate == null) || predicate(mi))); + public static MethodInfo GetMethod(string name, Type returnType, int parameterCount = 0, Func? predicate = null) => + GetMethod(name, parameterCount, mi => (mi.ReturnType == returnType) && ((predicate == null) || predicate(mi))); - public static MethodInfo GetMethodWithExpressionParameter(string name) => - GetMethod(name, 1, mi => - mi.GetParameters().Length == 2 && - mi.GetParameters()[1].ParameterType.GetTypeInfo().IsGenericType && - mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) && - mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetTypeInfo().IsGenericType && - mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func<,>) - ); + public static MethodInfo GetMethodWithExpressionParameter(string name) => + GetMethod(name, 1, mi => + mi.GetParameters().Length == 2 && + mi.GetParameters()[1].ParameterType.GetTypeInfo().IsGenericType && + mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) && + mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetTypeInfo().IsGenericType && + mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func<,>) + ); - public static MethodInfo GetMethodWithIntParameter(string name) => - GetMethod(name, 1, mi => - mi.GetParameters().Length == 2 && - mi.GetParameters()[1].ParameterType == typeof(int) - ); + public static MethodInfo GetMethodWithIntParameter(string name) => + GetMethod(name, 1, mi => + mi.GetParameters().Length == 2 && + mi.GetParameters()[1].ParameterType == typeof(int) + ); - public static MethodInfo GetMethod(string name, int parameterCount = 0, Func predicate = null) + public static MethodInfo GetMethod(string name, int parameterCount = 0, Func? predicate = null) + { + try + { + return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => + mi.GetParameters().Length == parameterCount + 1 && (predicate == null || predicate(mi))); + } + catch (Exception ex) { - try - { - return typeof(Queryable).GetTypeInfo().GetDeclaredMethods(name).Single(mi => - mi.GetParameters().Length == parameterCount + 1 && (predicate == null || predicate(mi))); - } - catch (Exception ex) - { - throw new Exception("Specific method not found: " + name, ex); - } + throw new Exception("Specific method not found: " + name, ex); } } } diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs index afc6b89e..4f90a753 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ParameterExpressionHelperTests.cs @@ -135,7 +135,7 @@ public void ParameterExpressionHelper_CreateParameterExpression(Type type, strin public void ParameterExpressionHelper_IsNullOrWhiteSpace(string input, bool expectedResult) { // Arrange and Act - bool result = ParameterExpressionHelper.IsNullOrWhiteSpace(input); + bool result = input.IsNullOrWhiteSpace(); // Assert Check.That(result).IsEqualTo(expectedResult);