views:

67

answers:

2

Hi there,

It says in the Unity manual...

ParameterOverride can be used only for constructors.

So why are the parameters of methods left out?

Cheers, Ian.

+1  A: 

In DI frameworks, we usually have constructor injection or property injection.

Constructor injection is when the framework constructing instances and automatically supplies instances matching the parameters of a constructor.

Property injection is when, after the instance is created, any property, with a type supported by the container, is automatically set to an instance of that type.

Parameters are usually not supported with properties, thus PropertyOverride only makes sense with constructor injection.

Update: method injection in Unity allows a method to be called on the instance passing in parameters to the method call:

container.RegisterType<DriveController>(
       new InjectionMethod("InitializeMe", 42.0, 
       new ResolvedParameter<ILogger>("SpecialLogger")));

The InjectionMethod class forces you to provide values for all the methods parameters. Using a ParameterOverride does not make much sense in this case since we already have provided explicit values for the resolver to use.

Note: a technical reason to why ParameterOverride only works with constructor parameters is that supporting overrides for methods have some problematic cases. Consider the following class:

public class Foo
{
      public Foo(IService service) { ... }
      public void Initialize(IService service) { ... }
}

container.Resolve<IFoo>(new ParameterOverride("service", new Service()));

Which parameter should be overridden?

If you need to provide parameter values when resolving, I would suggest using factory delegates instead. Converting the sample above:

container.RegisterInstance<Func<int, DriveController>>(
    number => {
                  var dc = new DriveController();
                  dc.InitializeMe(number, container.Resolve<ILogger>("SpecialLogger"));
                  return dc;
              });

var factory = container.Resolve<Func<int, DriveController>>();
var dc = factory(42);

I have not tried this with Unity. I assume it will work, at least it shows that there should be alternatives to providing parameter values at "resolve time".

Peter Lillevold
Hi Peter, with Unity, in addition to the two types of injection you mentioned there is also 'Method Injection'.http://msdn.microsoft.com/en-us/library/ff660882(v=PandP.20).aspx#specify_method_inj
Ian Warburton
@Ian - thanks! One learns something new every day :) See my updated answer...
Peter Lillevold
"Using a ParameterOverride does not make much sense in this case since we already have provided explicit values for the resolver to use."Couldn't the same argument be levelled at Constructor and Property parameter overrides which, of course, do exist?To put it another way, one can provide values for parameters when registering Constructors and Properties but these values can still be overridden at resolve time.
Ian Warburton
@Ian - I'm sure the Unity team could've implemented the same support for methods, I'm only speculating in why they didn't. My theory is because when using method injection, you always provide values explicitly, and should thus never need to override those values. Constructor parameters, on the contrary, always have *default* values which is whatever type is matched in the container. `ParameterOverride` provides a means to override those defaults. I also have a more technical theory as to why they only support constructor parameters, see my updated answer in a minute :)
Peter Lillevold
Thanks for your reply. Nice factory delegate! I'll be using that.I think your theory makes a bit of sense. However I'm not yet convinced that the difference between explicit param values and default param values is significant in this case. Even a default value ultimately resolves to a concrete value!I think the technical limitation as to why only constructor parameters are supported would easily be overcome if method injection parameter overrides were actually supported. The implementation would just make one specify a 'MethodOverride' just as one might specify a 'PropertyOverride'.
Ian Warburton
Yes, I agree, various `Override` types would've been part of the solution. But... I think, when you move down the factory delegate road, the need for overrides diminishes. We should strive to make our code independent of the container, since using it directly would be an extra dependency in itself. Instead, hiding the container behind delegates and injecting *those* into our classes is IMO the way to go, rather then calling `Resolve`.
Peter Lillevold
I agree as well. The Overrides stuff was added due to overwhelming user request, but in my own code I would absolutely use a separate factory. In fact, I deliberately made the override syntax messy / ugly, just to remind users that maybe this isn't a good idea. ;-)
Chris Tavares
@Chris - that is just cool. But do you think users get that? I think they see the feature and get awestruck at how "advanced" it is and then go ahead and use it because ... "it is in there, it is advanced, it must be good"!
Peter Lillevold
+1  A: 

The reason I left it out, quite honestly, was development & test time, plus the fact that method injection is used much, much less than constructor or property injection. In particular, our test and doc teams were holding on by their fingernails trying to keep up with the stuff I was throwing them as it was.

There's no technical reason to leave it out. The Override objects are extensible, so it's perfectly reasonable to create your own to override method parameter values if you really need it.

Chris Tavares
Thank you Chris!
Ian Warburton