From efaa34c34d27e41928eb020ead0a5f09e3bf0bd3 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 5 Feb 2023 11:03:14 +0100 Subject: [PATCH] Update AbstractDynamicLinqCustomTypeProvider to exclude null types (#665) * Update AbstractDynamicLinqCustomTypeProvider * . * . --- src/Directory.Build.props | 2 +- .../AbstractDynamicLinqCustomTypeProvider.cs | 233 +++++++++--------- .../Extensions/LinqExtensions.cs | 23 +- 3 files changed, 136 insertions(+), 122 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b4e615fc..143e1ce0 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ Copyright © ZZZ Projects en-us true - 10 + 11 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 811b7d10..ffe1ea81 100644 --- a/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs +++ b/src/System.Linq.Dynamic.Core/CustomTypeProviders/AbstractDynamicLinqCustomTypeProvider.cs @@ -1,155 +1,160 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Dynamic.Core.Extensions; using System.Linq.Dynamic.Core.Validation; using System.Reflection; -namespace System.Linq.Dynamic.Core.CustomTypeProviders +namespace System.Linq.Dynamic.Core.CustomTypeProviders; + +/// +/// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. +/// +[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] +public abstract class AbstractDynamicLinqCustomTypeProvider { /// - /// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core. + /// Finds the unique types marked with DynamicLinqTypeAttribute. /// - public abstract class AbstractDynamicLinqCustomTypeProvider + /// The assemblies to process. + /// + protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) { - /// - /// Finds the unique types marked with DynamicLinqTypeAttribute. - /// - /// The assemblies to process. - /// - protected IEnumerable FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable assemblies) - { - Check.NotNull(assemblies, nameof(assemblies)); + Check.NotNull(assemblies); #if !NET35 - assemblies = assemblies.Where(a => !a.IsDynamic); + assemblies = assemblies.Where(a => !a.IsDynamic); #endif - return GetAssemblyTypesWithDynamicLinqTypeAttribute(assemblies).Distinct().ToArray(); - } + return GetAssemblyTypesWithDynamicLinqTypeAttribute(assemblies).Distinct().ToArray(); + } - /// - /// Resolve any type which is registered in the current application domain. - /// - /// The assemblies to inspect. - /// The typename to resolve. - /// A resolved or null when not found. - protected Type? ResolveType(IEnumerable assemblies, string typeName) - { - Check.NotNull(assemblies, nameof(assemblies)); - Check.NotEmpty(typeName, nameof(typeName)); + /// + /// Resolve any type which is registered in the current application domain. + /// + /// The assemblies to inspect. + /// The typename to resolve. + /// A resolved or null when not found. + protected Type? ResolveType(IEnumerable assemblies, string typeName) + { + Check.NotNull(assemblies); + Check.NotEmpty(typeName); - foreach (var assembly in assemblies) + foreach (var assembly in assemblies) + { + var resolvedType = assembly.GetType(typeName, false, true); + if (resolvedType != null) { - Type resolvedType = assembly.GetType(typeName, false, true); - if (resolvedType != null) - { - return resolvedType; - } + return resolvedType; } - - return null; } - /// - /// Resolve a type by the simple name which is registered in the current application domain. - /// - /// The assemblies to inspect. - /// The simple typename to resolve. - /// A resolved or null when not found. - protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) + return null; + } + + /// + /// Resolve a type by the simple name which is registered in the current application domain. + /// + /// The assemblies to inspect. + /// The simple typename to resolve. + /// A resolved or null when not found. + protected Type? ResolveTypeBySimpleName(IEnumerable assemblies, string simpleTypeName) + { + Check.NotNull(assemblies); + Check.NotEmpty(simpleTypeName); + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); - Check.NotEmpty(simpleTypeName, nameof(simpleTypeName)); + var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); + var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); - foreach (var assembly in assemblies) + if (firstMatchingFullname != null) { - var fullNames = assembly.GetTypes().Select(t => t.FullName!).Distinct(); - var firstMatchingFullname = fullNames.FirstOrDefault(fn => fn.EndsWith($".{simpleTypeName}")); - - if (firstMatchingFullname != null) + var resolvedType = assembly.GetType(firstMatchingFullname, false, true); + if (resolvedType != null) { - var resolvedType = assembly.GetType(firstMatchingFullname, false, true); - if (resolvedType != null) - { - return resolvedType; - } + return resolvedType; } } - - return null; } + return null; + } + #if (WINDOWS_APP || UAP10_0 || NETSTANDARD) - /// - /// Gets the assembly types annotated with in an Exception friendly way. - /// - /// The assemblies to process. - /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + /// + /// Gets the assembly types annotated with in an Exception friendly way. + /// + /// The assemblies to process. + /// + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + { + Check.NotNull(assemblies); + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); + var definedTypes = Type.EmptyTypes; - foreach (var assembly in assemblies) + try + { + definedTypes = assembly.ExportedTypes.ToArray(); + } + catch (ReflectionTypeLoadException reflectionTypeLoadException) + { + definedTypes = reflectionTypeLoadException.Types.WhereNotNull().ToArray(); + } + catch { - Type[]? definedTypes = null; + // Ignore all other exceptions + } - try - { - definedTypes = assembly.ExportedTypes.Where(t => t.GetTypeInfo().IsDefined(typeof(DynamicLinqTypeAttribute), false)).ToArray(); - } - catch (ReflectionTypeLoadException reflectionTypeLoadException) - { - definedTypes = reflectionTypeLoadException.Types; - } - catch - { - // Ignore all other exceptions - } + var filteredAndDistinct = definedTypes + .Where(t => t.GetTypeInfo().IsDefined(typeof(DynamicLinqTypeAttribute), false)) + .Distinct(); - if (definedTypes != null && definedTypes.Length > 0) - { - foreach (var definedType in definedTypes) - { - yield return definedType; - } - } + foreach (var definedType in filteredAndDistinct) + { + yield return definedType; } } + } #else - /// - /// Gets the assembly types annotated with in an Exception friendly way. - /// - /// The assemblies to process. - /// - protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + /// + /// Gets the assembly types annotated with in an Exception friendly way. + /// + /// The assemblies to process. + /// + protected IEnumerable GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable assemblies) + { + Check.NotNull(assemblies); + +#if !NET5_0_OR_GREATER + assemblies = assemblies.Where(a => !a.GlobalAssemblyCache); // Skip System DLL's +#endif + + foreach (var assembly in assemblies) { - Check.NotNull(assemblies, nameof(assemblies)); + var definedTypes = Type.EmptyTypes; - foreach (var assembly in assemblies.Where(a => !a.GlobalAssemblyCache)) // Skip System DLL's + try { - Type[]? definedTypes = null; + definedTypes = assembly.GetExportedTypes().ToArray(); + } + catch (ReflectionTypeLoadException reflectionTypeLoadException) + { + definedTypes = reflectionTypeLoadException.Types.WhereNotNull().ToArray(); + } + catch + { + // Ignore all other exceptions + } - try - { - definedTypes = assembly - .GetExportedTypes() - .Where(t => t.IsDefined(typeof(DynamicLinqTypeAttribute), false)) - .ToArray(); - } - catch (ReflectionTypeLoadException reflectionTypeLoadException) - { - definedTypes = reflectionTypeLoadException.Types; - } - catch - { - // Ignore all other exceptions - } + var filteredAndDistinct = definedTypes + .Where(t => t.IsDefined(typeof(DynamicLinqTypeAttribute), false)) + .Distinct(); - if (definedTypes != null && definedTypes.Length > 0) - { - foreach (var definedType in definedTypes) - { - yield return definedType; - } - } + foreach (var definedType in filteredAndDistinct) + { + yield return definedType; } } -#endif } -} +#endif +} \ No newline at end of file diff --git a/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs index a0c0a5f3..c68ffee3 100644 --- a/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs +++ b/src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs @@ -1,13 +1,22 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Dynamic.Core.Validation; -namespace System.Linq.Dynamic.Core.Extensions +namespace System.Linq.Dynamic.Core.Extensions; + +[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] +internal static class LinqExtensions { - internal static class LinqExtensions + // Ex: collection.TakeLast(5); + public static IEnumerable TakeLast(this IList source, int n) { - // Ex: collection.TakeLast(5); - public static IEnumerable TakeLast(this IList source, int n) - { - return source.Skip(Math.Max(0, source.Count() - n)); - } + return source.Skip(Math.Max(0, source.Count() - n)); + } + + public static IEnumerable WhereNotNull(this IEnumerable sequence) + { + Check.NotNull(sequence); + + return sequence.Where(e => e != null)!; } } \ No newline at end of file