From 0fad9d646359c71f4d5e9443500fd9248ce10aa4 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 18 Nov 2020 16:57:23 -0600 Subject: [PATCH] Remove unnecessary GetTypeInfo from Microsoft.Extensions. (#44891) I also made a slight optimization to CallSiteFactory to use ToArray instead of ToList. --- .../ActivatorUtilities/ActivatorUtilities.cs | 10 +-- .../src/ConfigurationBinder.cs | 73 ++++++++++------------ .../src/UserSecretsConfigurationExtensions.cs | 6 +- .../tests/ConfigurationExtensionTest.cs | 6 +- .../src/ServiceLookup/CallSiteFactory.cs | 24 +++---- .../Expressions/ExpressionResolverBuilder.cs | 2 +- .../TestUtility/FileSystemOperationRecorder.cs | 4 +- .../src/HostFactoryResolver.cs | 6 +- .../src/OptionsServiceCollectionExtensions.cs | 7 +-- 9 files changed, 67 insertions(+), 71 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index 574fd89..1300db8 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -50,7 +50,7 @@ namespace Microsoft.Extensions.Internal ConstructorMatcher bestMatcher = default; - if (!instanceType.GetTypeInfo().IsAbstract) + if (!instanceType.IsAbstract) { foreach (ConstructorInfo? constructor in instanceType.GetConstructors()) { @@ -323,7 +323,7 @@ namespace Microsoft.Extensions.Internal for (int i = 0; i < argumentTypes.Length; i++) { bool foundMatch = false; - TypeInfo? givenParameter = argumentTypes[i].GetTypeInfo(); + Type? givenParameter = argumentTypes[i]; for (int j = 0; j < constructorParameters.Length; j++) { @@ -333,7 +333,7 @@ namespace Microsoft.Extensions.Internal continue; } - if (constructorParameters[j].ParameterType.GetTypeInfo().IsAssignableFrom(givenParameter)) + if (constructorParameters[j].ParameterType.IsAssignableFrom(givenParameter)) { foundMatch = true; parameterMap[j] = i; @@ -369,13 +369,13 @@ namespace Microsoft.Extensions.Internal int applyExactLength = 0; for (int givenIndex = 0; givenIndex != givenParameters.Length; givenIndex++) { - TypeInfo? givenType = givenParameters[givenIndex]?.GetType().GetTypeInfo(); + Type? givenType = givenParameters[givenIndex]?.GetType(); bool givenMatched = false; for (int applyIndex = applyIndexStart; givenMatched == false && applyIndex != _parameters.Length; ++applyIndex) { if (_parameterValues[applyIndex] == null && - _parameters[applyIndex].ParameterType.GetTypeInfo().IsAssignableFrom(givenType)) + _parameters[applyIndex].ParameterType.IsAssignableFrom(givenType)) { givenMatched = true; _parameterValues[applyIndex] = givenParameters[givenIndex]; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index 171a8df..4d2e5cf 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -14,6 +14,8 @@ namespace Microsoft.Extensions.Configuration /// public static class ConfigurationBinder { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + /// /// Attempts to bind the configuration instance to a new instance of type T. /// If this configuration section has a value, that will be used. @@ -179,7 +181,7 @@ namespace Microsoft.Extensions.Configuration { if (instance != null) { - foreach (PropertyInfo property in GetAllProperties(instance.GetType().GetTypeInfo())) + foreach (PropertyInfo property in GetAllProperties(instance.GetType())) { BindProperty(property, instance, configuration, options); } @@ -214,20 +216,18 @@ namespace Microsoft.Extensions.Configuration } } - private static object BindToCollection(TypeInfo typeInfo, IConfiguration config, BinderOptions options) + private static object BindToCollection(Type type, IConfiguration config, BinderOptions options) { - Type type = typeof(List<>).MakeGenericType(typeInfo.GenericTypeArguments[0]); - object instance = Activator.CreateInstance(type); - BindCollection(instance, type, config, options); + Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments[0]); + object instance = Activator.CreateInstance(genericType); + BindCollection(instance, genericType, config, options); return instance; } // Try to create an array/dictionary instance to back various collection interfaces private static object AttemptBindToCollectionInterfaces(Type type, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = type.GetTypeInfo(); - - if (!typeInfo.IsInterface) + if (!type.IsInterface) { return null; } @@ -236,13 +236,13 @@ namespace Microsoft.Extensions.Configuration if (collectionInterface != null) { // IEnumerable is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(IReadOnlyDictionary<,>), type); if (collectionInterface != null) { - Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1]); + Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1]); object instance = Activator.CreateInstance(dictionaryType); BindDictionary(instance, dictionaryType, config, options); return instance; @@ -251,7 +251,7 @@ namespace Microsoft.Extensions.Configuration collectionInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type); if (collectionInterface != null) { - object instance = Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1])); + object instance = Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1])); BindDictionary(instance, collectionInterface, config, options); return instance; } @@ -260,21 +260,21 @@ namespace Microsoft.Extensions.Configuration if (collectionInterface != null) { // IReadOnlyCollection is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type); if (collectionInterface != null) { // ICollection is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(IEnumerable<>), type); if (collectionInterface != null) { // IEnumerable is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } return null; @@ -349,26 +349,24 @@ namespace Microsoft.Extensions.Configuration private static object CreateInstance(Type type) { - TypeInfo typeInfo = type.GetTypeInfo(); - - if (typeInfo.IsInterface || typeInfo.IsAbstract) + if (type.IsInterface || type.IsAbstract) { throw new InvalidOperationException(SR.Format(SR.Error_CannotActivateAbstractOrInterface, type)); } if (type.IsArray) { - if (typeInfo.GetArrayRank() > 1) + if (type.GetArrayRank() > 1) { throw new InvalidOperationException(SR.Format(SR.Error_UnsupportedMultidimensionalArray, type)); } - return Array.CreateInstance(typeInfo.GetElementType(), 0); + return Array.CreateInstance(type.GetElementType(), 0); } - if (!typeInfo.IsValueType) + if (!type.IsValueType) { - bool hasDefaultConstructor = typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); + bool hasDefaultConstructor = type.GetConstructors(DeclaredOnlyLookup).Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); if (!hasDefaultConstructor) { throw new InvalidOperationException(SR.Format(SR.Error_MissingParameterlessConstructor, type)); @@ -387,12 +385,10 @@ namespace Microsoft.Extensions.Configuration private static void BindDictionary(object dictionary, Type dictionaryType, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = dictionaryType.GetTypeInfo(); - // IDictionary is guaranteed to have exactly two parameters - Type keyType = typeInfo.GenericTypeArguments[0]; - Type valueType = typeInfo.GenericTypeArguments[1]; - bool keyTypeIsEnum = keyType.GetTypeInfo().IsEnum; + Type keyType = dictionaryType.GenericTypeArguments[0]; + Type valueType = dictionaryType.GenericTypeArguments[1]; + bool keyTypeIsEnum = keyType.IsEnum; if (keyType != typeof(string) && !keyTypeIsEnum) { @@ -400,7 +396,7 @@ namespace Microsoft.Extensions.Configuration return; } - PropertyInfo setter = typeInfo.GetDeclaredProperty("Item"); + PropertyInfo setter = dictionaryType.GetProperty("Item", DeclaredOnlyLookup); foreach (IConfigurationSection child in config.GetChildren()) { object item = BindInstance( @@ -426,11 +422,9 @@ namespace Microsoft.Extensions.Configuration private static void BindCollection(object collection, Type collectionType, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = collectionType.GetTypeInfo(); - // ICollection is guaranteed to have exactly one parameter - Type itemType = typeInfo.GenericTypeArguments[0]; - MethodInfo addMethod = typeInfo.GetDeclaredMethod("Add"); + Type itemType = collectionType.GenericTypeArguments[0]; + MethodInfo addMethod = collectionType.GetMethod("Add", DeclaredOnlyLookup); foreach (IConfigurationSection section in config.GetChildren()) { @@ -497,7 +491,7 @@ namespace Microsoft.Extensions.Configuration return true; } - if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { if (string.IsNullOrEmpty(value)) { @@ -550,17 +544,16 @@ namespace Microsoft.Extensions.Configuration private static Type FindOpenGenericInterface(Type expected, Type actual) { - TypeInfo actualTypeInfo = actual.GetTypeInfo(); - if (actualTypeInfo.IsGenericType && + if (actual.IsGenericType && actual.GetGenericTypeDefinition() == expected) { return actual; } - IEnumerable interfaces = actualTypeInfo.ImplementedInterfaces; + Type[] interfaces = actual.GetInterfaces(); foreach (Type interfaceType in interfaces) { - if (interfaceType.GetTypeInfo().IsGenericType && + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == expected) { return interfaceType; @@ -569,16 +562,16 @@ namespace Microsoft.Extensions.Configuration return null; } - private static IEnumerable GetAllProperties(TypeInfo type) + private static IEnumerable GetAllProperties(Type type) { var allProperties = new List(); do { - allProperties.AddRange(type.DeclaredProperties); - type = type.BaseType.GetTypeInfo(); + allProperties.AddRange(type.GetProperties(DeclaredOnlyLookup)); + type = type.BaseType; } - while (type != typeof(object).GetTypeInfo()); + while (type != typeof(object)); return allProperties; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs index 0da3963..bdd31d0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs @@ -29,7 +29,7 @@ namespace Microsoft.Extensions.Configuration /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional: false, reloadOnChange: false); + => configuration.AddUserSecrets(typeof(T).Assembly, optional: false, reloadOnChange: false); /// /// @@ -47,7 +47,7 @@ namespace Microsoft.Extensions.Configuration /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration, bool optional) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional, reloadOnChange: false); + => configuration.AddUserSecrets(typeof(T).Assembly, optional, reloadOnChange: false); /// /// @@ -66,7 +66,7 @@ namespace Microsoft.Extensions.Configuration /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration, bool optional, bool reloadOnChange) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional, reloadOnChange); + => configuration.AddUserSecrets(typeof(T).Assembly, optional, reloadOnChange); /// /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs index 6f59604..44fa286 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Configuration.UserSecrets.Test SetSecret(TestSecretsId, configKey, randValue); var config = new ConfigurationBuilder() - .AddUserSecrets(typeof(ConfigurationExtensionTest).GetTypeInfo().Assembly) + .AddUserSecrets(typeof(ConfigurationExtensionTest).Assembly) .Build(); Assert.Equal(randValue, config[configKey]); @@ -86,12 +86,12 @@ namespace Microsoft.Extensions.Configuration.UserSecrets.Test { var ex = Assert.Throws(() => new ConfigurationBuilder().AddUserSecrets()); - Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(string).GetTypeInfo().Assembly.GetName().Name), + Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(string).Assembly.GetName().Name), ex.Message); ex = Assert.Throws(() => new ConfigurationBuilder().AddUserSecrets(typeof(JObject).Assembly)); - Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(JObject).GetTypeInfo().Assembly.GetName().Name), + Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(JObject).Assembly.GetName().Name), ex.Message); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs index f9e7e42..a73b14a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs @@ -15,7 +15,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup internal class CallSiteFactory { private const int DefaultSlot = 0; - private readonly List _descriptors; + private readonly ServiceDescriptor[] _descriptors; private readonly ConcurrentDictionary _callSiteCache = new ConcurrentDictionary(); private readonly Dictionary _descriptorLookup = new Dictionary(); @@ -24,7 +24,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup public CallSiteFactory(IEnumerable descriptors) { _stackGuard = new StackGuard(); - _descriptors = descriptors.ToList(); + _descriptors = descriptors.ToArray(); Populate(); } @@ -32,19 +32,19 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { foreach (ServiceDescriptor descriptor in _descriptors) { - TypeInfo serviceTypeInfo = descriptor.ServiceType.GetTypeInfo(); - if (serviceTypeInfo.IsGenericTypeDefinition) + Type serviceType = descriptor.ServiceType; + if (serviceType.IsGenericTypeDefinition) { - TypeInfo implementationTypeInfo = descriptor.ImplementationType?.GetTypeInfo(); + Type implementationType = descriptor.ImplementationType; - if (implementationTypeInfo == null || !implementationTypeInfo.IsGenericTypeDefinition) + if (implementationType == null || !implementationType.IsGenericTypeDefinition) { throw new ArgumentException( SR.Format(SR.OpenGenericServiceRequiresOpenGenericImplementation, descriptor.ServiceType), "descriptors"); } - if (implementationTypeInfo.IsAbstract || implementationTypeInfo.IsInterface) + if (implementationType.IsAbstract || implementationType.IsInterface) { throw new ArgumentException( SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); @@ -53,11 +53,11 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup else if (descriptor.ImplementationInstance == null && descriptor.ImplementationFactory == null) { Debug.Assert(descriptor.ImplementationType != null); - TypeInfo implementationTypeInfo = descriptor.ImplementationType.GetTypeInfo(); + Type implementationType = descriptor.ImplementationType; - if (implementationTypeInfo.IsGenericTypeDefinition || - implementationTypeInfo.IsAbstract || - implementationTypeInfo.IsInterface) + if (implementationType.IsGenericTypeDefinition || + implementationType.IsAbstract || + implementationType.IsInterface) { throw new ArgumentException( SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); @@ -160,7 +160,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { int slot = 0; // We are going in reverse so the last service in descriptor list gets slot 0 - for (int i = _descriptors.Count - 1; i >= 0; i--) + for (int i = _descriptors.Length - 1; i >= 0; i--) { ServiceDescriptor descriptor = _descriptors[i]; ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs index 1453db21..e737107 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs @@ -193,7 +193,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup private static Expression Convert(Expression expression, Type type, bool forceValueTypeConversion = false) { // Don't convert if the expression is already assignable - if (type.GetTypeInfo().IsAssignableFrom(expression.Type.GetTypeInfo()) + if (type.IsAssignableFrom(expression.Type) && (!expression.Type.GetTypeInfo().IsValueType || !forceValueTypeConversion)) { return expression; diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs index c3c7781..cef2ebb 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs @@ -8,6 +8,8 @@ namespace Microsoft.Extensions.FileSystemGlobbing.Tests.TestUtility { internal class FileSystemOperationRecorder { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + public IList> Records = new List>(); public void Add(string action, object values) @@ -17,7 +19,7 @@ namespace Microsoft.Extensions.FileSystemGlobbing.Tests.TestUtility {"action", action } }; - foreach (var p in values.GetType().GetTypeInfo().DeclaredProperties) + foreach (var p in values.GetType().GetProperties(DeclaredOnlyLookup)) { record[p.Name] = p.GetValue(values); } diff --git a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs index f70dc1a..bb095c3 100644 --- a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs +++ b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs @@ -8,6 +8,8 @@ namespace Microsoft.Extensions.Hosting { internal class HostFactoryResolver { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + public static readonly string BuildWebHost = nameof(BuildWebHost); public static readonly string CreateWebHostBuilder = nameof(CreateWebHostBuilder); public static readonly string CreateHostBuilder = nameof(CreateHostBuilder); @@ -35,7 +37,7 @@ namespace Microsoft.Extensions.Hosting return null; } - var factory = programType.GetTypeInfo().GetDeclaredMethod(name); + var factory = programType.GetMethod(name, DeclaredOnlyLookup); if (!IsFactory(factory)) { return null; @@ -105,7 +107,7 @@ namespace Microsoft.Extensions.Hosting return null; } var hostType = host.GetType(); - var servicesProperty = hostType.GetTypeInfo().GetDeclaredProperty("Services"); + var servicesProperty = hostType.GetProperty("Services", DeclaredOnlyLookup); return (IServiceProvider)servicesProperty.GetValue(host); } } diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs index 10341d4..ca10c35 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs @@ -147,14 +147,13 @@ namespace Microsoft.Extensions.DependencyInjection => services.ConfigureOptions(typeof(TConfigureOptions)); private static bool IsAction(Type type) - => (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Action<>)); + => (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Action<>)); private static IEnumerable FindConfigurationServices(Type type) { IEnumerable serviceTypes = type - .GetTypeInfo() - .ImplementedInterfaces - .Where(t => t.GetTypeInfo().IsGenericType) + .GetInterfaces() + .Where(t => t.IsGenericType) .Where(t => t.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) || t.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) || -- 2.7.4