Last active
February 5, 2021 11:07
-
-
Save vtml/f42fe6ec033597a8b0fb3b5910a70df4 to your computer and use it in GitHub Desktop.
Sitecore Super Power Friendly Dependency Injection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text.RegularExpressions; | |
namespace Isobar.Foundation.SitecoreUtilities.Extensions | |
{ | |
public interface IReflectionExtensions | |
{ | |
Assembly[] GetAssemblies(IEnumerable<string> assemblyFilters); | |
IEnumerable<Type> GetTypesImplementing(Type implementsType, IEnumerable<Assembly> assemblies, params string[] classFilter); | |
IEnumerable<Type> GetTypesImplementing(Type implementsType, params Assembly[] assemblies); | |
/// <summary> | |
/// Extract the default implemented interface. Returns the interface implemented if there's only one, otherwise it will return the closest one with the name matched | |
/// </summary> | |
/// <param name="concreteClass"></param> | |
/// <returns></returns> | |
Type GetDefaultImplementedInterface(Type concreteClass); | |
IEnumerable<Type> GetExportedTypes(Assembly assembly); | |
/// <summary> | |
/// Checks if a string matches a wildcard argument (using regex) | |
/// </summary> | |
bool IsWildcardMatch(string input, string wildcard); | |
/// <summary> | |
/// Filter out Interface, Abstracts and Generic Types | |
/// https://stackoverflow.com/questions/80247/implementations-of-interface-through-reflection | |
/// </summary> | |
/// <param name="testType"></param> | |
/// <returns></returns> | |
bool IsRealClass(Type testType); | |
/// <summary> | |
/// Uses reflection to get the field value from an object. | |
/// https://stackoverflow.com/questions/3303126/how-to-get-the-value-of-private-field-in-c | |
/// </summary> | |
/// <param name="type">The instance type.</param> | |
/// <param name="instance">The instance object.</param> | |
/// <param name="fieldName">The field's name which is to be fetched.</param> | |
/// <returns>The field value from the object.</returns> | |
object GetInstanceField(Type type, object instance, string fieldName); | |
} | |
public class ReflectionExtensions : IReflectionExtensions | |
{ | |
public Assembly[] GetAssemblies(IEnumerable<string> assemblyFilters) | |
{ | |
var assemblies = new List<Assembly>(); | |
foreach (var assemblyFilter in assemblyFilters) | |
{ | |
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().Where(assembly => IsWildcardMatch(assembly.GetName().Name, assemblyFilter)).ToArray()); | |
} | |
return assemblies.ToArray(); | |
} | |
public IEnumerable<Type> GetTypesImplementing(Type implementsType, IEnumerable<Assembly> assemblies, params string[] classFilter) | |
{ | |
var types = GetTypesImplementing(implementsType, assemblies.ToArray()); | |
if (classFilter != null && classFilter.Any()) | |
{ | |
types = types.Where(type => classFilter.Any(filter => IsWildcardMatch(type.FullName, filter))); | |
} | |
return types; | |
} | |
public IEnumerable<Type> GetTypesImplementing(Type implementsType, params Assembly[] assemblies) | |
{ | |
if (assemblies == null || assemblies.Length == 0) | |
{ | |
return new Type[0]; | |
} | |
var targetType = implementsType; | |
return assemblies | |
.Where(assembly => !assembly.IsDynamic) | |
.SelectMany(GetExportedTypes) | |
.Where(type => !type.IsAbstract && !type.IsGenericTypeDefinition && targetType.IsAssignableFrom(type)) | |
.ToArray(); | |
} | |
public Type GetDefaultImplementedInterface(Type concreteClass) | |
{ | |
if (!IsRealClass(concreteClass)) return null; | |
var concreteClassName = concreteClass.Name; | |
var mockUpInterfaceName = string.Format("I{0}", concreteClassName); | |
var defaultInterface = concreteClass.GetInterfaces(); | |
if (defaultInterface.Length.Equals(1)) return defaultInterface.FirstOrDefault(); | |
var closesetMatchedInterface = defaultInterface.Where(i => i.Name.StartsWith(mockUpInterfaceName, StringComparison.OrdinalIgnoreCase)).OrderBy(i => i.Name.Length - mockUpInterfaceName.Length); | |
var defaultInterfaceList = closesetMatchedInterface as IList<Type> ?? closesetMatchedInterface.ToList(); | |
return defaultInterfaceList.Any() ? defaultInterfaceList.FirstOrDefault() : null; | |
} | |
public IEnumerable<Type> GetExportedTypes(Assembly assembly) | |
{ | |
try | |
{ | |
return assembly.GetExportedTypes(); | |
} | |
catch (NotSupportedException) | |
{ | |
// A type load exception would typically happen on an Anonymously Hosted DynamicMethods | |
// Assembly and it would be safe to skip this exception. | |
return Type.EmptyTypes; | |
} | |
catch (FileLoadException) | |
{ | |
// The assembly points to a not found assembly - ignore and continue | |
return Type.EmptyTypes; | |
} | |
catch (ReflectionTypeLoadException ex) | |
{ | |
// Return the types that could be loaded. Types can contain null values. | |
return ex.Types.Where(type => type != null); | |
} | |
catch (Exception ex) | |
{ | |
// Throw a more descriptive message containing the name of the assembly. | |
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to load types from assembly {0}. {1}", assembly.FullName, ex.Message), ex); | |
} | |
} | |
public bool IsWildcardMatch(string input, string wildcard) | |
{ | |
return input == wildcard || Regex.IsMatch(input, "^" + Regex.Escape(wildcard).Replace("\\*", ".*").Replace("\\?", ".") + "$", RegexOptions.IgnoreCase); | |
} | |
public bool IsRealClass(Type testType) | |
{ | |
return testType.IsAbstract == false && testType.IsGenericTypeDefinition == false && testType.IsInterface == false; | |
} | |
public object GetInstanceField(Type type, object instance, string fieldName) | |
{ | |
const BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; | |
var field = type.GetField(fieldName, bindFlags); | |
return field != null ? field.GetValue(instance) : null; | |
} | |
} | |
} |
Line 131 IsWIldCardMatch you have a bug out there, about to submit a correct solution.
Thank you, that'll be awesome.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 131 IsWIldCardMatch you have a bug out there, about to submit a correct solution.