Skip to content

Commit

Permalink
## Reflection [1.9.0] - 2023-10-21
Browse files Browse the repository at this point in the history
- Changed: `ITypeCache` become `IEnumerable<Type>`
- Changed: `TypeLoader` unified assembly loading, `ExcludeByPatterns` fix
- Added: `TypeCache.Create` method to create type cache with customizations
- Added: `Invoker` creates compiled cached delegates more easy than `CodeCompiler`
  • Loading branch information
petriashev committed Oct 22, 2023
1 parent b3874a4 commit c2b73b7
Show file tree
Hide file tree
Showing 10 changed files with 413 additions and 140 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ ___
Name | MicroElements.Collections.Sources
Description | MicroElements source only package:
Collection extensions: NotNull, Iterate, Execute, WhereNotNull, Materialize, IncludeByWildcardPatterns, ExcludeByWildcardPatterns.
Special collections: TwoLayerCache.
Special collections: Cache, TwoLayerCache, PollingCache.
Github | [https://github.com/micro-elements/MicroElements.Shared/tree/master/src/MicroElements.Collections.Sources](https://github.com/micro-elements/MicroElements.Shared/tree/master/src/MicroElements.Collections.Sources)
Status | [![NuGetVersion](https://img.shields.io/nuget/v/MicroElements.Collections.Sources.svg)](https://www.nuget.org/packages/MicroElements.Collections.Sources) ![NuGetDownloads](https://img.shields.io/nuget/dt/MicroElements.Collections.Sources.svg)

Expand Down
2 changes: 1 addition & 1 deletion src/MicroElements.Collections.Sources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

MicroElements source only package:
Collection extensions: NotNull, Iterate, Execute, WhereNotNull, Materialize, IncludeByWildcardPatterns, ExcludeByWildcardPatterns.
Special collections: TwoLayerCache.
Special collections: Cache, TwoLayerCache, PollingCache.

## Extensions

Expand Down
6 changes: 6 additions & 0 deletions src/MicroElements.Reflection.Sources/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [1.9.0] - 2023-10-21
- Changed: `ITypeCache` become `IEnumerable<Type>`
- Changed: `TypeLoader` unified assembly loading, `ExcludeByPatterns` fix
- Added: `TypeCache.Create` method to create type cache with customizations
- Added: `Invoker` creates compiled cached delegates more easy than `CodeCompiler`

## [1.8.0] - 2022-12-17
- Changed: `MicroElements.Reflection.TypeCache` renamed to `MicroElements.Reflection.TypeCaching`
- Added: `LazyTypeCache`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<TargetFramework>netstandard2.1</TargetFramework>

<PackageId>MicroElements.Reflection.Sources</PackageId>
<PackageVersion>1.8.0</PackageVersion>
<PackageVersion>1.9.0</PackageVersion>
<Description>MicroElements source only package: Reflection. Classes: TypeExtensions, TypeCheck, ObjectExtensions, Expressions, CodeCompiler, FriendlyName.</Description>
<PackageTags>MicroElements Reflection Expressions</PackageTags>

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#endregion
#region Supressions

#pragma warning disable
// ReSharper disable All
#endregion

namespace MicroElements.Reflection.TypeCaching
{
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -18,7 +20,7 @@ namespace MicroElements.Reflection.TypeCaching
using MicroElements.Collections.Extensions.NotNull;

/// <summary> Represents type cache abstraction. </summary>
internal interface ITypeCache
internal interface ITypeCache: IEnumerable<Type>
{
Type? GetType(string typeName);
string? GetName(Type type);
Expand Down Expand Up @@ -125,6 +127,12 @@ public void AddType(Type type, string typeName)
aliasForType[type] = typeName;
}
}

/// <inheritdoc />
public IEnumerator<Type> GetEnumerator() => _types.GetEnumerator();

/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

/// <summary> Lazy cache. Gets values only on first attempt. </summary>
Expand All @@ -149,6 +157,12 @@ public LazyTypeCache(Func<ITypeCache> factory)

/// <inheritdoc />
public void AddType(Type type, string typeName) => _typeCache.Value.AddType(type, typeName);

/// <inheritdoc />
public IEnumerator<Type> GetEnumerator() => _typeCache.Value.GetEnumerator();

/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

/// <summary> Type cache that gets value from parent if it was not found in current cache. </summary>
Expand All @@ -168,6 +182,23 @@ public HierarchicalTypeCache(ITypeCache parent, ITypeCache typeCache)
public string? GetName(Type type) => _typeCache.GetName(type) ?? _parent.GetName(type);

public void AddType(Type type, string typeName) => _typeCache.AddType(type, typeName);

/// <inheritdoc />
public IEnumerator<Type> GetEnumerator()
{
foreach (var type in _typeCache)
{
yield return type;
}

foreach (var type in _parent)
{
yield return type;
}
}

/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

internal partial class TypeCache
Expand All @@ -185,6 +216,12 @@ public static ITypeCache CreateAppDomainCache(bool reloadOnAssemblyLoad = false)
AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => typeCache.Invalidate();
return typeCache;
}

/// <summary> Creates type cache from AssemblySource and TypeFilter. </summary>
public static ITypeCache Create(AssemblySource assemblySource, TypeFilters typeFilter)
{
return new LazyTypeCache(() => new TypeCache(assemblySource.LoadTypes(typeFilter)));
}
}

internal static class TypeCacheExtensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static IReadOnlyCollection<Type> LoadTypes(
.GetTypes(typeFilters, messages);
return types;
}

/// <summary>
/// Loads assemblies according <paramref name="assemblySource"/>.
/// 1. Gets all assemblies from <see cref="AppDomain.CurrentDomain"/> if <see cref="AssemblySource.LoadFromDomain"/> is true.
Expand All @@ -56,42 +56,33 @@ public static IEnumerable<Assembly> LoadAssemblies(
{
assemblySource.AssertArgumentNotNull(nameof(assemblySource));

IEnumerable<Assembly> assemblies = Array.Empty<Assembly>();

if (assemblySource.LoadFromDomain)
assemblies = AppDomain.CurrentDomain.GetAssemblies();

if (assemblySource.LoadFromDirectory != null)
IEnumerable<Assembly> assemblies = Array.Empty<Assembly>()
.ConcatIf(assemblySource.LoadFromDomain, AppDomain.CurrentDomain.GetAssemblies)
.ConcatIf(assemblySource.LoadFromDirectory != null, AssembliesFromDirectory)
.ConcatIf(assemblySource.Assemblies != null, () => assemblySource.Assemblies)
.IncludeByPatterns(assembly => assembly.FullName, assemblySource.IncludePatterns)
.ExcludeByPatterns(assembly => assembly.FullName, assemblySource.ExcludePatterns)
.Distinct();

return assemblies;

IEnumerable<Assembly> AssembliesFromDirectory()
{
if (!Directory.Exists(assemblySource.LoadFromDirectory))
throw new DirectoryNotFoundException($"Assembly ScanDirectory {assemblySource.LoadFromDirectory} is not exists.");

var searchPatterns = assemblySource.SearchPatterns ?? new[] { "*.dll" };
var searchPatterns = assemblySource.FileSearchPatterns ?? new[] { "*.dll" };
var assembliesFromDirectory =
searchPatterns
.SelectMany(filePattern => Directory.EnumerateFiles(assemblySource.LoadFromDirectory, filePattern, SearchOption.TopDirectoryOnly))
.SelectMany(filePattern => Directory.EnumerateFiles(assemblySource.LoadFromDirectory!, filePattern, SearchOption.TopDirectoryOnly))
.IncludeByPatterns(fileName => fileName, assemblySource.IncludePatterns)
.ExcludeByPatterns(fileName => fileName, assemblySource.ExcludePatterns)
.Select(assemblyFile => TryLoadAssemblyFrom(assemblyFile, messages)!)
.Where(assembly => assembly != null);

assemblies = assemblies.Concat(assembliesFromDirectory);
return assembliesFromDirectory;
}

if (assemblySource.Assemblies is { Count: > 0 })
{
assemblies = assemblies.Concat(assemblySource.Assemblies);
}

assemblies = assemblies
.IncludeByPatterns(assembly => assembly.FullName, assemblySource.IncludePatterns)
.ExcludeByPatterns(assembly => assembly.FullName, assemblySource.ExcludePatterns);

assemblies = assemblies.Distinct();

return assemblies;
}

/// <summary>
/// Gets types from assembly list according type filters.
/// </summary>
Expand Down Expand Up @@ -170,27 +161,12 @@ public static IEnumerable<Type> GetDefinedTypesSafe(this Assembly assembly, ICol
}
}
}

/// <summary>
/// Assembly source.
/// </summary>
internal class AssemblySource
internal partial class AssemblySource
{
/// <summary>
/// Gets an empty assembly source. No assemblies, no filters.
/// </summary>
public static AssemblySource Empty { get; } = new (
loadFromDomain: false,
loadFromDirectory: null);

/// <summary>
/// All assemblies from AppDomain.
/// </summary>
public static AssemblySource AppDomain { get; } = new (
loadFromDomain: true,
loadFromDirectory: null,
filterByTypeFilters: true);

/// <summary> Load assemblies from <see cref="System.AppDomain.CurrentDomain"/>. </summary>
public bool LoadFromDomain { get; set; }

Expand All @@ -200,7 +176,7 @@ internal class AssemblySource
/// <summary>
/// Optional file patterns for loading from directory.
/// </summary>
public IReadOnlyCollection<string>? SearchPatterns { get; set; }
public IReadOnlyCollection<string>? FileSearchPatterns { get; set; }

/// <summary>
/// <see cref="Assembly.FullName"/> wildcard include patterns.
Expand All @@ -219,37 +195,44 @@ internal class AssemblySource
/// </summary>
public IReadOnlyCollection<Assembly>? Assemblies { get; set; }

/// <summary>
/// Filter assemblies after type filtering and take only assemblies that owns filtered types.
/// </summary>
public bool FilterByTypeFilters { get; set; } = true;

/// <summary>
/// Initializes a new instance of the <see cref="AssemblySource"/> class.
/// </summary>
/// <param name="loadFromDomain">Optional load assemblies from <see cref="System.AppDomain.CurrentDomain"/>.</param>
/// <param name="loadFromDirectory">Optional load assemblies from provided directory.</param>
/// <param name="searchPatterns">Optional file patterns for loading from directory.</param>
/// <param name="assemblyFilters">Optional assembly filters.</param>
/// <param name="fileSearchPatterns">Optional file patterns for loading from directory.</param>
/// <param name="assemblies">User provided assemblies.</param>
/// <param name="filterByTypeFilters">Filter assemblies after type filtering and take only assemblies that owns filtered types.</param>
public AssemblySource(
bool loadFromDomain = false,
string? loadFromDirectory = null,
IReadOnlyCollection<string>? searchPatterns = null,
IReadOnlyCollection<Assembly>? assemblies = null,
bool filterByTypeFilters = true)
IReadOnlyCollection<string>? fileSearchPatterns = null,
IReadOnlyCollection<Assembly>? assemblies = null)
{
LoadFromDomain = loadFromDomain;

LoadFromDirectory = loadFromDirectory;
SearchPatterns = searchPatterns;
FileSearchPatterns = fileSearchPatterns;

Assemblies = assemblies;
FilterByTypeFilters = filterByTypeFilters;
}
}

internal partial class AssemblySource
{
/// <summary> Gets an empty assembly source. No assemblies, no filters. </summary>
public static AssemblySource Empty { get; } = new (loadFromDomain: false);

/// <summary> All assemblies from AppDomain. </summary>
public static AssemblySource AppDomain { get; } = new (loadFromDomain: true);

/// <summary> All assemblies from AppDomain excluding system assemblies. </summary>
public static AssemblySource AppDomainExcludingSystem { get; } = new ()
{
LoadFromDomain = true,
ExcludePatterns = new []{ "System.*", "Microsoft.*" }
};
}

/// <summary>
/// Type filters.
/// </summary>
Expand All @@ -263,7 +246,7 @@ internal class TypeFilters
IsPublic = true,
FullNameExcludes = new[] { "<*" }
};

/// <summary> Include only public types. </summary>
public bool IsPublic { get; set; }

Expand All @@ -273,7 +256,7 @@ internal class TypeFilters
/// <summary> Exclude types that <see cref="Type.FullName"/> matches filters. </summary>
public IReadOnlyCollection<string>? FullNameExcludes { get; set; }
}

/// <summary>
/// Provides methods for filtering.
/// </summary>
Expand All @@ -283,6 +266,13 @@ internal static class Filtering

internal static bool FileNameMatchesPattern(string filename, string pattern) => Regex.IsMatch(Path.GetFileName(filename) ?? string.Empty, WildcardToRegex(pattern));

internal static IEnumerable<T> ConcatIf<T>(this IEnumerable<T> values, bool predicate, Func<IEnumerable<T>?> valuesFactory)
{
if (predicate && valuesFactory() is {} valuesToAdd)
return values.Concat(valuesToAdd);
return values;
}

internal static IEnumerable<T> IncludeByPatterns<T>(this IEnumerable<T> values, Func<T, string> filterComponent, IReadOnlyCollection<string>? includePatterns = null)
{
if (includePatterns == null)
Expand All @@ -294,7 +284,7 @@ internal static IEnumerable<T> ExcludeByPatterns<T>(this IEnumerable<T> values,
{
if (excludePatterns == null)
return values;
return values.Where(value => excludePatterns.Any(excludePattern => !FileNameMatchesPattern(filterComponent(value), excludePattern)));
return values.Where(value => excludePatterns.All(excludePattern => !FileNameMatchesPattern(filterComponent(value), excludePattern)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

<ItemGroup>
<PackageReference Include="MicroElements.CodeContracts.Sources" Version="1.3.0" PrivateAssets="all" />
<PackageReference Include="MicroElements.Collections.Sources" Version="1.8.0" PrivateAssets="all" />
<PackageReference Include="MicroElements.Reflection.Sources" Version="1.8.0" PrivateAssets="all" />
<PackageReference Include="MicroElements.Collections.Sources" Version="1.10.0" PrivateAssets="all" />
<PackageReference Include="MicroElements.Reflection.Sources" Version="1.9.0" PrivateAssets="all" />
<PackageReference Include="MicroElements.Text.Sources" Version="1.0.0" PrivateAssets="all" />
</ItemGroup>

Expand Down
Loading

0 comments on commit c2b73b7

Please sign in to comment.