This commit is contained in:
Eugene Sadovoi 2017-10-11 20:22:26 -04:00
Родитель 802e215413
Коммит bfaed1ef05
5 изменённых файлов: 102 добавлений и 199 удалений

Просмотреть файл

@ -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&lt;User&gt;, and the
/// corresponding definition was SomeType&lt;TSomething&gt;, 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);
}
}
}
}