DependencyAttribute and virtual properties

Jul 16, 2013 at 10:09 AM
Hi, guys,

I'd like to override the dependency resolution of injected property in the inherited class
I wonder why the construct below doesn't work.

class A
{
[Dependency]
public virtual SomeClass SomeProp { get; set; }
}

class B : A
{
[Dependency("OtherInjection")]
public override SomeClass SomeProp { get; set; }
}

Why when I create instance of B during resolving, SomeProp is initialized from default resolution not using named resolution "OtherInjection"?
Jul 17, 2013 at 6:12 AM
Edited Jul 17, 2013 at 6:12 AM
It looks like all properties in the inheritance hierarchy are extracted and any properties in the hierarchy annotated with a DependencyResolutionAttribute are built up.

I'm not sure if this is by design or if it is a bug; I wasn't able to track down any description of what the expected behavior should be.

In any case, one approach you could take would be to use an abstract base class and have each subclass use their own DependencyAttribute. However, that is not very maintainable if you have multiple dependencies and properties and changes in the class hierarchy but might work in a simple case.

A better approach would be to not use DependencyAttribute and use programmatic configuration. This has the benefit of decoupling your classes from Unity and it can do exactly what I think you want:
    // Let's use a Logger for example purposes
    public interface ILogger { }
    public class Logger : ILogger { }

    public class SomeClass
    {
        public ILogger Logger { get; private set; }

        public SomeClass(ILogger logger)
        {
            Logger = logger;
        }

        public SomeClass() { }
    }

    public class A
    {
        public virtual SomeClass SomeProp { get; set; }
    }

    public class B : A
    {
        public override SomeClass SomeProp { get; set; }
    }

    IUnityContainer container = new UnityContainer();
    container.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager());

    container.RegisterType<SomeClass>(new InjectionConstructor());
    container.RegisterType<SomeClass>("OtherInjection", new InjectionConstructor(typeof(ILogger)));

    // this works without attributes
    container.RegisterType<A>(new InjectionProperty("SomeProp",
        new ResolvedParameter<SomeClass>()));

    container.RegisterType<B>(new InjectionProperty("SomeProp", 
        new ResolvedParameter<SomeClass>("OtherInjection")));
    
    // SomeProp has an injected ILogger
    B b = container.Resolve<B>();

    // SomeProp does not have an injected ILogger
    A a = container.Resolve<A>();

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 17, 2013 at 7:22 AM
Hi Randy,

Thanks for the reply.
But the second approach is also not very maintainable in case of big number of injected properties and deep class hierarchy.
So adding of new property requires changes of the all other class registrations in the hierarchy.
Jul 17, 2013 at 1:24 PM
Edited Jul 17, 2013 at 1:24 PM
If you want the highest level of maintanability then constructor injection would be the way to go instead of property injection; constructor injection can work more unobtrusively than property injection (although that could also depend on the requirements).

Unless I'm missing something you shouldn't have to rewire the whole object graph if a single property was added. If I want to add a new property to class B and configure it for injection I can just add the property and then add a new InjectionProperty:
public class B : A
{
    public override SomeClass SomeProp { get; set; }
    public SomeClass AnotherProp { get; set; }
}

container.RegisterType<B>(new InjectionProperty("AnotherProp", new ResolvedParameter<SomeClass>()),
    new InjectionProperty("SomeProp", new ResolvedParameter<SomeClass>("OtherInjection"))); 

Using attributes, I would have to to add the attribute instead of an InjectionProperty which would be a bit less code and be located in one space so it's a bit easier but not a huge difference, IMO. Also, I personally prefer to not have my application code reference Unity.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to