Skip to content

Commit

Permalink
Update AbstractDynamicLinqCustomTypeProvider to exclude null types (#665
Browse files Browse the repository at this point in the history
)

* Update AbstractDynamicLinqCustomTypeProvider

* .

* .
  • Loading branch information
StefH authored Feb 5, 2023
1 parent f7b42ed commit efaa34c
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 122 deletions.
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Copyright>Copyright © ZZZ Projects</Copyright>
<DefaultLanguage>en-us</DefaultLanguage>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>10</LangVersion>
<LangVersion>11</LangVersion>
<Nullable>enable</Nullable>
<PackageIcon>logo.png</PackageIcon>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// The abstract DynamicLinqCustomTypeProvider which is used by the DefaultDynamicLinqCustomTypeProvider and can be used by a custom TypeProvider like in .NET Core.
/// </summary>
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public abstract class AbstractDynamicLinqCustomTypeProvider
{
/// <summary>
/// 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.
/// </summary>
public abstract class AbstractDynamicLinqCustomTypeProvider
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable<Assembly> assemblies)
{
/// <summary>
/// Finds the unique types marked with DynamicLinqTypeAttribute.
/// </summary>
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> FindTypesMarkedWithDynamicLinqTypeAttribute(IEnumerable<Assembly> 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();
}

/// <summary>
/// Resolve any type which is registered in the current application domain.
/// </summary>
/// <param name="assemblies">The assemblies to inspect.</param>
/// <param name="typeName">The typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
protected Type? ResolveType(IEnumerable<Assembly> assemblies, string typeName)
{
Check.NotNull(assemblies, nameof(assemblies));
Check.NotEmpty(typeName, nameof(typeName));
/// <summary>
/// Resolve any type which is registered in the current application domain.
/// </summary>
/// <param name="assemblies">The assemblies to inspect.</param>
/// <param name="typeName">The typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
protected Type? ResolveType(IEnumerable<Assembly> 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;
}

/// <summary>
/// Resolve a type by the simple name which is registered in the current application domain.
/// </summary>
/// <param name="assemblies">The assemblies to inspect.</param>
/// <param name="simpleTypeName">The simple typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
protected Type? ResolveTypeBySimpleName(IEnumerable<Assembly> assemblies, string simpleTypeName)
return null;
}

/// <summary>
/// Resolve a type by the simple name which is registered in the current application domain.
/// </summary>
/// <param name="assemblies">The assemblies to inspect.</param>
/// <param name="simpleTypeName">The simple typename to resolve.</param>
/// <returns>A resolved <see cref="Type"/> or null when not found.</returns>
protected Type? ResolveTypeBySimpleName(IEnumerable<Assembly> 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)
/// <summary>
/// Gets the assembly types annotated with <see cref="DynamicLinqTypeAttribute"/> in an Exception friendly way.
/// </summary>
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly> assemblies)
/// <summary>
/// Gets the assembly types annotated with <see cref="DynamicLinqTypeAttribute"/> in an Exception friendly way.
/// </summary>
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly> 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
/// <summary>
/// Gets the assembly types annotated with <see cref="DynamicLinqTypeAttribute"/> in an Exception friendly way.
/// </summary>
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly> assemblies)
/// <summary>
/// Gets the assembly types annotated with <see cref="DynamicLinqTypeAttribute"/> in an Exception friendly way.
/// </summary>
/// <param name="assemblies">The assemblies to process.</param>
/// <returns><see cref="IEnumerable{Type}" /></returns>
protected IEnumerable<Type> GetAssemblyTypesWithDynamicLinqTypeAttribute(IEnumerable<Assembly> 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
}
23 changes: 16 additions & 7 deletions src/System.Linq.Dynamic.Core/Extensions/LinqExtensions.cs
Original file line number Diff line number Diff line change
@@ -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<T> TakeLast<T>(this IList<T> source, int n)
{
// Ex: collection.TakeLast(5);
public static IEnumerable<T> TakeLast<T>(this IList<T> source, int n)
{
return source.Skip(Math.Max(0, source.Count() - n));
}
return source.Skip(Math.Max(0, source.Count() - n));
}

public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> sequence)
{
Check.NotNull(sequence);

return sequence.Where(e => e != null)!;
}
}

0 comments on commit efaa34c

Please sign in to comment.