From bfaed1ef05c86a62ee99daf75166d8c35d0cbbe4 Mon Sep 17 00:00:00 2001 From: Eugene Sadovoi Date: Wed, 11 Oct 2017 20:22:26 -0400 Subject: [PATCH] Performance optimizations --- .../Creation/ConstructorSelectorPolicyBase.cs | 24 +-- .../Method/MethodSelectorPolicyBase.cs | 1 + src/Utility/ReflectionHelper.cs | 174 ------------------ tests/Unity.Tests/ParameterMatcherFixture.cs | 19 +- .../TestSupport/MethodReflectionHelper.cs | 83 +++++++++ 5 files changed, 102 insertions(+), 199 deletions(-) delete mode 100644 src/Utility/ReflectionHelper.cs create mode 100644 tests/Unity.Tests/TestSupport/MethodReflectionHelper.cs diff --git a/src/ObjectBuilder/Strategies/BuildPlan/Creation/ConstructorSelectorPolicyBase.cs b/src/ObjectBuilder/Strategies/BuildPlan/Creation/ConstructorSelectorPolicyBase.cs index cd8c9b0d..58125403 100644 --- a/src/ObjectBuilder/Strategies/BuildPlan/Creation/ConstructorSelectorPolicyBase.cs +++ b/src/ObjectBuilder/Strategies/BuildPlan/Creation/ConstructorSelectorPolicyBase.cs @@ -59,20 +59,19 @@ namespace Unity.ObjectBuilder.Strategies.BuildPlan.Creation private static ConstructorInfo FindInjectionConstructor(Type typeToConstruct) { - ReflectionHelper typeToConstructReflector = new ReflectionHelper(typeToConstruct); - - ConstructorInfo[] injectionConstructors = typeToConstructReflector.InstanceConstructors - .Where(ctor => ctor.IsDefined( - typeof(TInjectionConstructorMarkerAttribute), - true)) - .ToArray(); - switch (injectionConstructors.Length) + var constructors = typeToConstruct.GetTypeInfo() + .DeclaredConstructors + .Where(c => c.IsStatic == false && c.IsPublic && + c.IsDefined(typeof(TInjectionConstructorMarkerAttribute), + true)) + .ToArray(); + switch (constructors.Length) { case 0: return null; case 1: - return injectionConstructors[0]; + return constructors[0]; default: throw new InvalidOperationException( @@ -85,9 +84,10 @@ namespace Unity.ObjectBuilder.Strategies.BuildPlan.Creation private static ConstructorInfo FindLongestConstructor(Type typeToConstruct) { - ReflectionHelper typeToConstructReflector = new ReflectionHelper(typeToConstruct); - - ConstructorInfo[] constructors = typeToConstructReflector.InstanceConstructors.ToArray(); + ConstructorInfo[] constructors = typeToConstruct.GetTypeInfo() + .DeclaredConstructors + .Where(c => c.IsStatic == false && c.IsPublic) + .ToArray(); Array.Sort(constructors, new ConstructorLengthComparer()); switch (constructors.Length) diff --git a/src/ObjectBuilder/Strategies/BuildPlan/Method/MethodSelectorPolicyBase.cs b/src/ObjectBuilder/Strategies/BuildPlan/Method/MethodSelectorPolicyBase.cs index 295dbdf6..8efa4646 100644 --- a/src/ObjectBuilder/Strategies/BuildPlan/Method/MethodSelectorPolicyBase.cs +++ b/src/ObjectBuilder/Strategies/BuildPlan/Method/MethodSelectorPolicyBase.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using Unity.Builder; using Unity.Policy; +using Unity.Utility; namespace Unity.ObjectBuilder.Strategies.BuildPlan.Method { diff --git a/src/Utility/ReflectionHelper.cs b/src/Utility/ReflectionHelper.cs deleted file mode 100644 index 14add209..00000000 --- a/src/Utility/ReflectionHelper.cs +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Unity.Utility -{ - /// - /// A small helper class to encapsulate details of the - /// reflection API, particularly around generics. - /// - internal class ReflectionHelper - { - /// - /// Create a new instance that - /// lets you look at information about the given type. - /// - /// Type to do reflection on. - public ReflectionHelper(Type typeToReflect) - { - Type = typeToReflect; - TypeInfo = typeToReflect.GetTypeInfo(); - } - - /// - /// The object we're reflecting over. - /// - public TypeInfo TypeInfo { get; } - - - /// - /// The object we're reflecting over. - /// - public Type Type { get; } - - /// - /// Is this type generic? - /// - public bool IsGenericType => TypeInfo.IsGenericType; - - /// - /// Is this type an open generic (no type parameter specified) - /// - public bool IsOpenGeneric => TypeInfo.IsGenericType && - TypeInfo.ContainsGenericParameters; - - /// - /// Is this type an array type? - /// - public bool IsArray => Type.IsArray; - - /// - /// Is this type an array of generic elements? - /// - public bool IsGenericArray => IsArray && ArrayElementType.GetTypeInfo().IsGenericParameter; - - /// - /// The type of the elements in this type (if it's an array). - /// - public Type ArrayElementType => Type.GetElementType(); - - /// - /// Test the given object, looking at - /// the parameters. Determine if any of the parameters are - /// open generic types that need type attributes filled in. - /// - /// The method to check. - /// True if any of the parameters are open generics. False if not. - public static bool MethodHasOpenGenericParameters(MethodBase method) - { - foreach (ParameterInfo param in (method ?? throw new ArgumentNullException(nameof(method))).GetParameters()) - { - var r = new ReflectionHelper(param.ParameterType); - if (r.IsOpenGeneric) - { - return true; - } - } - return false; - } - - /// - /// If this type is an open generic, use the - /// given array to - /// determine what the required closed type is and return that. - /// - /// If the parameter is not an open type, just - /// return this parameter's type. - /// Type arguments to substitute in for - /// the open type parameters. - /// Corresponding closed type of this parameter. - public Type GetClosedParameterType(Type[] genericArguments) - { - // Prior version of the framework returned both generic type arguments and parameters - // through one mechanism, now they are broken out. May want to consider different reflection - // helpers instead of this case statement. - - if (IsOpenGeneric) - { - Type[] typeArgs = TypeInfo.IsGenericTypeDefinition ? TypeInfo.GenericTypeParameters : TypeInfo.GenericTypeArguments; - for (int i = 0; i < typeArgs.Length; ++i) - { - typeArgs[i] = (genericArguments ?? throw new ArgumentNullException(nameof(genericArguments)))[typeArgs[i].GenericParameterPosition]; - } - return Type.GetGenericTypeDefinition().MakeGenericType(typeArgs); - } - if (TypeInfo.IsGenericParameter) - { - return genericArguments[Type.GenericParameterPosition]; - } - if (IsArray && ArrayElementType.GetTypeInfo().IsGenericParameter) - { - int rank; - if ((rank = Type.GetArrayRank()) == 1) - { - // work around to the fact that Type.MakeArrayType() != Type.MakeArrayType(1) - return genericArguments[Type.GetElementType().GenericParameterPosition] - .MakeArrayType(); - } - - return genericArguments[Type.GetElementType().GenericParameterPosition] - .MakeArrayType(rank); - } - return Type; - } - - /// - /// Given a generic argument name, return the corresponding type for this - /// closed type. For example, if the current type is SomeType<User>, and the - /// corresponding definition was SomeType<TSomething>, calling this method - /// and passing "TSomething" will return typeof(User). - /// - /// Name of the generic parameter. - /// Type of the corresponding generic parameter, or null if there - /// is no matching name. - public Type GetNamedGenericParameter(string parameterName) - { - TypeInfo openType = Type.GetGenericTypeDefinition().GetTypeInfo(); - Type result = null; - int index = -1; - - foreach (var genericArgumentType in openType.GenericTypeParameters) - { - if (genericArgumentType.GetTypeInfo().Name == parameterName) - { - index = genericArgumentType.GenericParameterPosition; - break; - } - } - if (index != -1) - { - result = TypeInfo.GenericTypeArguments[index]; - } - return result; - } - - /// - /// Returns all the public constructors defined for the current reflected . - /// - /// - /// An enumeration of ConstructorInfo objects representing all the public instance constructors defined for the - /// current reflected , but not including the type initializer (static constructor). - /// - public IEnumerable InstanceConstructors - { - get - { - return TypeInfo.DeclaredConstructors.Where(c => c.IsStatic == false && c.IsPublic); - } - } - } -} diff --git a/tests/Unity.Tests/ParameterMatcherFixture.cs b/tests/Unity.Tests/ParameterMatcherFixture.cs index 13db21c1..e961a14d 100644 --- a/tests/Unity.Tests/ParameterMatcherFixture.cs +++ b/tests/Unity.Tests/ParameterMatcherFixture.cs @@ -2,10 +2,9 @@ using System; using System.Collections.Generic; -using Microsoft.Practices.Unity.Utility; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Unity; using Unity.Injection; +using Unity.Utility; namespace Microsoft.Practices.Unity.Tests { @@ -18,37 +17,31 @@ namespace Microsoft.Practices.Unity.Tests [TestMethod] public void EmptyParameterListMatches() { - ParameterMatcher matcher = new ParameterMatcher(Parameters()); - - Assert.IsTrue(matcher.Matches(Types())); + Assert.IsTrue(Parameters().Matches(Types())); } [TestMethod] public void MismatchedParameterListsDontMatch() { - ParameterMatcher matcher = new ParameterMatcher(Parameters()); - Assert.IsFalse(matcher.Matches(Types(typeof(int)))); + Assert.IsFalse(Parameters().Matches(Types(typeof(int)))); } [TestMethod] public void SameLengthDifferentTypesDontMatch() { - ParameterMatcher matcher = new ParameterMatcher(Parameters(typeof(int))); - Assert.IsFalse(matcher.Matches(Types(typeof(string)))); + Assert.IsFalse(Parameters(typeof(int)).Matches(Types(typeof(string)))); } [TestMethod] public void SameLengthSameTypesMatch() { - ParameterMatcher matcher = new ParameterMatcher(Parameters(typeof(int), typeof(string))); - Assert.IsTrue(matcher.Matches(Types(typeof(int), typeof(string)))); + Assert.IsTrue(Parameters(typeof(int), typeof(string)).Matches(Types(typeof(int), typeof(string)))); } [TestMethod] public void OpenGenericTypesMatch() { - ParameterMatcher matcher = new ParameterMatcher(Parameters(typeof(ICommand<>), typeof(ICommand<>))); - Assert.IsTrue(matcher.Matches(Types(typeof(ICommand<>), typeof(ICommand<>)))); + Assert.IsTrue(Parameters(typeof(ICommand<>), typeof(ICommand<>)).Matches(Types(typeof(ICommand<>), typeof(ICommand<>)))); } private static InjectionParameterValue[] Parameters(params Type[] types) diff --git a/tests/Unity.Tests/TestSupport/MethodReflectionHelper.cs b/tests/Unity.Tests/TestSupport/MethodReflectionHelper.cs new file mode 100644 index 00000000..6f490ee3 --- /dev/null +++ b/tests/Unity.Tests/TestSupport/MethodReflectionHelper.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Unity +{ + /// + /// Helper class to wrap common reflection stuff dealing with + /// methods. + /// + internal class MethodReflectionHelper + { + private readonly MethodBase method; + + /// + /// Create a new instance that + /// lets us do more reflection stuff on that method. + /// + /// The method to reflect on. + public MethodReflectionHelper(MethodBase method) + { + this.method = method; + } + + /// + /// Returns true if any of the parameters of this method + /// are open generics. + /// + public bool MethodHasOpenGenericParameters + { + get + { + return GetParameterReflectors().Any(r => r.IsOpenGeneric); + } + } + + /// + /// Return the of each parameter for this + /// method. + /// + /// Sequence of objects, one for + /// each parameter in order. + public IEnumerable ParameterTypes + { + get + { + foreach (ParameterInfo param in method.GetParameters()) + { + yield return param.ParameterType; + } + } + } + + /// + /// Given our set of generic type arguments, + /// + /// The generic type arguments. + /// An array with closed parameter types. + public Type[] GetClosedParameterTypes(Type[] genericTypeArguments) + { + return GetClosedParameterTypesSequence(genericTypeArguments).ToArray(); + } + + private IEnumerable GetParameterReflectors() + { + foreach (ParameterInfo pi in method.GetParameters()) + { + yield return new ParameterReflectionHelper(pi); + } + } + + private IEnumerable GetClosedParameterTypesSequence(Type[] genericTypeArguments) + { + foreach (ParameterReflectionHelper r in GetParameterReflectors()) + { + yield return r.GetClosedParameterType(genericTypeArguments); + } + } + } +}