Register<IA, A>();
class B { public IA A {get;set;}}
//container inject this property because IA was registered
In autofac you can do
builder.RegisterType<A>().InjectProperties();
for this.
Is there any e开发者_开发知识库xtension for unity to do this? Or may be extension which I can use as sample for implement this feature by myself?
This is not a simple task. To resolve it you should change Unity's default behaviour of the property selector policy. You can change it. This is what I can propose
namespace Microsoft.Practices.Unity.ObjectBuilder
{
public class ResolveBecouseWeCanPropertySelectorPolicy : PropertySelectorBase<DependencyResolutionAttribute>
{
private readonly IUnityContainer container;
public ResolveBecouseWeCanPropertySelectorPolicy(IUnityContainer container) {
this.container = container;
}
public override IEnumerable<SelectedProperty> SelectProperties(IBuilderContext context, IPolicyList resolverPolicyDestination) {
Type t = context.BuildKey.Type;
foreach (
PropertyInfo prop in
t.GetProperties(BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance)) {
if (prop.GetIndexParameters().Length == 0 &&
prop.CanWrite
&& prop.IsDefined(typeof (DependencyResolutionAttribute), false)
) //Default behaviour
{
yield return CreateSelectedProperty(context, resolverPolicyDestination, prop);
}
//Alternate behaviour
else if (prop.GetIndexParameters().Length == 0 &&
prop.CanWrite &&
container.IsRegistered(prop.PropertyType)//don't mind about Dependency attribute if we can resolve it - we would
) {
{
yield return CreateSelectedPropertyForResolveBecouseWeCan(context, resolverPolicyDestination, prop);
}
}
}
}
private SelectedProperty CreateSelectedProperty(IBuilderContext context, IPolicyList resolverPolicyDestination, PropertyInfo property) {
return DoCreateSelectedProperty(property, resolverPolicyDestination, CreateResolver(property), context);
}
private static SelectedProperty CreateSelectedPropertyForResolveBecouseWeCan(IBuilderContext context, IPolicyList resolverPolicyDestination, PropertyInfo property) {
IDependencyResolverPolicy dependencyResolverPolicy = new DependencyAttribute().CreateResolver(property.PropertyType);
return DoCreateSelectedProperty(property, resolverPolicyDestination, dependencyResolverPolicy, context);
}
private static SelectedProperty DoCreateSelectedProperty(PropertyInfo property, IPolicyList resolverPolicyDestination, IDependencyResolverPolicy dependencyResolverPolicy, IBuilderContext context) {
string key = Guid.NewGuid().ToString();
var result = new SelectedProperty(property, key);
resolverPolicyDestination.Set( dependencyResolverPolicy, key);
DependencyResolverTrackerPolicy.TrackKey(context.PersistentPolicies,
context.BuildKey,
key);
return result;
}
protected override IDependencyResolverPolicy CreateResolver(PropertyInfo property)
{
var attributes =
property.GetCustomAttributes(typeof (DependencyResolutionAttribute), false)
.OfType<DependencyResolutionAttribute>()
.ToList();
Debug.Assert(attributes.Count == 1);
return attributes[0].CreateResolver(property.PropertyType);
}
}
}
This is modified DefaultUnityPropertySelectorPolicy wich you can find in source code of unity.
After that you need to redefine default behaviour by using UnityContainerExtension
mechanism.
public class ResolveBecouseWeCanUnityContainerExtension : UnityContainerExtension {
protected override void Initialize() {
Context.Policies.SetDefault<IPropertySelectorPolicy>(
new ResolveBecouseWeCanPropertySelectorPolicy(Container));
}
}
So now let's imagine that you have following classes
public interface IConcreteService {
int Val { get; set; }
}
public class ConcreteService : IConcreteService {
public int Val { get; set; }
public ConcreteService() {
}
}
public class B {
//no attribute
public IConcreteService ConcreteService { get; set; }
public int SomeVal { get; set; }
}
so now this test should pass
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
container.RegisterType<IConcreteService, ConcreteService>();
var b = new B();
container.BuildUp(b);
Assert.IsNotNull(b.ConcreteService);
}
But you should understand that this one would not
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.RegisterType<IConcreteService, ConcreteService>();
var b0 = new B();
container.BuildUp(b0);
Assert.IsNull(b0.ConcreteService);
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
var b = new B();
container.BuildUp(b);
Assert.IsNotNull(b.ConcreteService); //dies becouse plan cashed
}
}
Update
I've played a little bit more and found out how to make this test work
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.RegisterType<IConcreteService, ConcreteService>();
var b0 = new B();
container.BuildUp(b0);
Assert.IsNull(b0.ConcreteService);
var b = new B();
container.BuildUpAndResolveAllWeCan(b);
Assert.IsNotNull(b.ConcreteService);
//check if we have no broken something and that it will work second time
var b1 = new B();
container.BuildUp(b1);
Assert.IsNull(b1.ConcreteService);
var b2 = new B();
container.BuildUpAndResolveAllWeCan(b2);
Assert.IsNotNull(b2.ConcreteService);
}
}
this is can be done in following way
public static class UnityExtensions {
public static T BuildUpAndResolveAllWeCan<T>(this IUnityContainer container, T existing) {
return BuildUpAndResolveAllWeCan(container, existing, null) ;
}
public static T BuildUpAndResolveAllWeCan<T>(this IUnityContainer container, T existing, string name) {
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
//we are adding __BuildUpResolveAllWeCan__ to create new IBuildPlanPolicy for type T
//and IPropertySelectorPolicy is ResolveBecouseWeCanPropertySelectorPolicy
//this will be cached so it will not hurt the performance
var buildedUp = container.BuildUp(existing, (name ?? string.Empty) + "__BuildUpResolveAllWeCan__");
container.AddExtension(new CleanUnityContainerExtension());
return buildedUp;
}
}
and adding clean up extension
public class CleanUnityContainerExtension : UnityContainerExtension {
protected override void Initialize() {
Context.Policies.SetDefault<IPropertySelectorPolicy>(
new DefaultUnityPropertySelectorPolicy());
}
}
You can download source file from here http://92.248.232.12/UnitTest1.zip
精彩评论