Performance optimizations
This commit is contained in:
Родитель
802e215413
Коммит
bfaed1ef05
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A small helper class to encapsulate details of the
|
||||
/// reflection API, particularly around generics.
|
||||
/// </summary>
|
||||
internal class ReflectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ReflectionHelper"/> instance that
|
||||
/// lets you look at information about the given type.
|
||||
/// </summary>
|
||||
/// <param name="typeToReflect">Type to do reflection on.</param>
|
||||
public ReflectionHelper(Type typeToReflect)
|
||||
{
|
||||
Type = typeToReflect;
|
||||
TypeInfo = typeToReflect.GetTypeInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TypeInfo"/> object we're reflecting over.
|
||||
/// </summary>
|
||||
public TypeInfo TypeInfo { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Type"/> object we're reflecting over.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this type generic?
|
||||
/// </summary>
|
||||
public bool IsGenericType => TypeInfo.IsGenericType;
|
||||
|
||||
/// <summary>
|
||||
/// Is this type an open generic (no type parameter specified)
|
||||
/// </summary>
|
||||
public bool IsOpenGeneric => TypeInfo.IsGenericType &&
|
||||
TypeInfo.ContainsGenericParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Is this type an array type?
|
||||
/// </summary>
|
||||
public bool IsArray => Type.IsArray;
|
||||
|
||||
/// <summary>
|
||||
/// Is this type an array of generic elements?
|
||||
/// </summary>
|
||||
public bool IsGenericArray => IsArray && ArrayElementType.GetTypeInfo().IsGenericParameter;
|
||||
|
||||
/// <summary>
|
||||
/// The type of the elements in this type (if it's an array).
|
||||
/// </summary>
|
||||
public Type ArrayElementType => Type.GetElementType();
|
||||
|
||||
/// <summary>
|
||||
/// Test the given <see cref="MethodBase"/> object, looking at
|
||||
/// the parameters. Determine if any of the parameters are
|
||||
/// open generic types that need type attributes filled in.
|
||||
/// </summary>
|
||||
/// <param name="method">The method to check.</param>
|
||||
/// <returns>True if any of the parameters are open generics. False if not.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this type is an open generic, use the
|
||||
/// given <paramref name="genericArguments"/> array to
|
||||
/// determine what the required closed type is and return that.
|
||||
/// </summary>
|
||||
/// <remarks>If the parameter is not an open type, just
|
||||
/// return this parameter's type.</remarks>
|
||||
/// <param name="genericArguments">Type arguments to substitute in for
|
||||
/// the open type parameters.</param>
|
||||
/// <returns>Corresponding closed type of this parameter.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
/// <param name="parameterName">Name of the generic parameter.</param>
|
||||
/// <returns>Type of the corresponding generic parameter, or null if there
|
||||
/// is no matching name.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the public constructors defined for the current reflected <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// An enumeration of <see cref="ConstructorInfo"/> ConstructorInfo objects representing all the public instance constructors defined for the
|
||||
/// current reflected <see cref="Type"/>, but not including the type initializer (static constructor).
|
||||
/// </value>
|
||||
public IEnumerable<ConstructorInfo> InstanceConstructors
|
||||
{
|
||||
get
|
||||
{
|
||||
return TypeInfo.DeclaredConstructors.Where(c => c.IsStatic == false && c.IsPublic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to wrap common reflection stuff dealing with
|
||||
/// methods.
|
||||
/// </summary>
|
||||
internal class MethodReflectionHelper
|
||||
{
|
||||
private readonly MethodBase method;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="MethodReflectionHelper"/> instance that
|
||||
/// lets us do more reflection stuff on that method.
|
||||
/// </summary>
|
||||
/// <param name="method">The method to reflect on.</param>
|
||||
public MethodReflectionHelper(MethodBase method)
|
||||
{
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any of the parameters of this method
|
||||
/// are open generics.
|
||||
/// </summary>
|
||||
public bool MethodHasOpenGenericParameters
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetParameterReflectors().Any(r => r.IsOpenGeneric);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the <see cref="System.Type"/> of each parameter for this
|
||||
/// method.
|
||||
/// </summary>
|
||||
/// <returns>Sequence of <see cref="System.Type"/> objects, one for
|
||||
/// each parameter in order.</returns>
|
||||
public IEnumerable<Type> ParameterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ParameterInfo param in method.GetParameters())
|
||||
{
|
||||
yield return param.ParameterType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given our set of generic type arguments,
|
||||
/// </summary>
|
||||
/// <param name="genericTypeArguments">The generic type arguments.</param>
|
||||
/// <returns>An array with closed parameter types. </returns>
|
||||
public Type[] GetClosedParameterTypes(Type[] genericTypeArguments)
|
||||
{
|
||||
return GetClosedParameterTypesSequence(genericTypeArguments).ToArray();
|
||||
}
|
||||
|
||||
private IEnumerable<ParameterReflectionHelper> GetParameterReflectors()
|
||||
{
|
||||
foreach (ParameterInfo pi in method.GetParameters())
|
||||
{
|
||||
yield return new ParameterReflectionHelper(pi);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Type> GetClosedParameterTypesSequence(Type[] genericTypeArguments)
|
||||
{
|
||||
foreach (ParameterReflectionHelper r in GetParameterReflectors())
|
||||
{
|
||||
yield return r.GetClosedParameterType(genericTypeArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче