I was trying to clean up some accessability stuff in my code, and inadvertently broke Unity dependency injection. After a while I realized that I marked some public properties t
UPDATE FOR Enterprise Library 5.0
As rally52rs warned might happen, the upgrade to EntLib5.0 breaks his implementation. Using the same approach as Rally did, I reflected on the new code base and worked up the following 5.0 compatible version of the InternalConstructorSelectorPolicy.
Note that my version specifically limits itself to internal constructors in the FindLongestConstructor method. On this point my code is functionally different from Rally's.
public class InternalConstructorSelectorPolicy : IConstructorSelectorPolicy, IBuilderPolicy
{
private IDependencyResolverPolicy CreateResolver(ParameterInfo parameter)
{
List attrs = parameter.GetCustomAttributes(false).OfType().ToList();
if (attrs.Count > 0)
{
return attrs[0].CreateResolver(parameter.ParameterType);
}
return new NamedTypeDependencyResolverPolicy(parameter.ParameterType, null);
}
private SelectedConstructor CreateSelectedConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination, ConstructorInfo ctor)
{
SelectedConstructor result = new SelectedConstructor(ctor);
foreach (ParameterInfo param in ctor.GetParameters())
{
string key = Guid.NewGuid().ToString();
IDependencyResolverPolicy policy = this.CreateResolver(param);
resolverPolicyDestination.Set(policy, key);
DependencyResolverTrackerPolicy.TrackKey(resolverPolicyDestination, context.BuildKey, key);
result.AddParameterKey(key);
}
return result;
}
private static ConstructorInfo FindInjectionConstructor(Type typeToConstruct)
{
ConstructorInfo[] injectionConstructors = typeToConstruct
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(delegate(ConstructorInfo ctor)
{
return ctor.IsDefined(typeof(InjectionConstructorAttribute), true);
}).ToArray();
switch (injectionConstructors.Length)
{
case 0:
return null;
case 1:
return injectionConstructors[0];
}
throw new InvalidOperationException(string.Format("Multiple constructors found for {0}" , typeToConstruct.Name ));
}
private static ConstructorInfo FindLongestConstructor(Type typeToConstruct)
{
var constructors =
Array.FindAll(
typeToConstruct.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic),
ctor => !ctor.IsFamily && !ctor.IsPrivate); //Filter out protected and private constructors
Array.Sort(constructors, new ConstructorLengthComparer());
switch (constructors.Length)
{
case 0:
return null;
case 1:
return constructors[0];
}
int paramLength = constructors[0].GetParameters().Length;
if (constructors[1].GetParameters().Length == paramLength)
{
throw new InvalidOperationException(string.Format("Ambiguous constructor found for {0}", typeToConstruct.Name));
}
return constructors[0];
}
public SelectedConstructor SelectConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination)
{
Type typeToConstruct = context.BuildKey.Type;
ConstructorInfo ctor = FindInjectionConstructor(typeToConstruct) ?? FindLongestConstructor(typeToConstruct);
if (ctor != null)
{
return this.CreateSelectedConstructor(context, resolverPolicyDestination, ctor);
}
return null;
}
// Nested Types
private class ConstructorLengthComparer : IComparer
{
// Methods
public int Compare(ConstructorInfo x, ConstructorInfo y)
{
return (y.GetParameters().Length - x.GetParameters().Length);
}
}
}