What is the best way to inject a runtime parameter

3,196 views
Skip to first unread message

Tod

unread,
Oct 22, 2009, 6:58:12 PM10/22/09
to ninject
After my program starts I have to read an integer from an instrument.
I need to create a class that uses this number in the constructor. The
constructor for this class takes a single int parameter.

public MyClass(int hwReadValue)
{
//...do something with hwReadValue
}

As a newbie the only way I know to use Ninject 2.0 to do this would
be with a ConstructorArgument
var my_hw_arg = new ConstructorArgument
("hwReadValue",the_value_i_read);
InstanceOfMyClass = IocContainer.Kernel.Get<IMyClass>(my_hw_arg );

Question:
1. This works, but is it the cleanest way to get a class that takes a
single runtime primitive argument? Is there any other approach that
doesn't require a dependency on the name of the parameter never
changing? I would much prefer to use an attribute based approach.

Ben Ellis

unread,
Oct 23, 2009, 4:43:09 PM10/23/09
to nin...@googlegroups.com
Tod,

Personally I find if you're injecting primative values into a constructor,
the class is possibly not a good candidate for IoC.

If it is a constant primative value (such as a configuration value) you can
add a binding parameter to add it on construction.

kernel.Bind<IMyService>().To<MyConcreteImplemention>().WithConstructorArgument("constructorArgumentName",
constantValue);

If the primative value changes during the lifetime of the application,
you're probably better off using the factory/provider pattern to create
you're objects and bind only the factory to the kernel, and use the factory
to create new instances of your class. e.g.

In Initialization / Module,

kernel.Bind<IMyObjectFactory>.To<MyObjectFactory>()

In a class that uses MyObject,

public class MyClassThatUsesObjects
{
private readonly IMyObjectFactory objFactory;

public MyClassThatUsesObjects(IMyObjectFactory objFactory)
{
this.objFactory = objFactory;
}

public void MethodThatUsesMyObject()
{
IMyObject obj = this.objFactory.CreateNew(param1, param2, param3,
etc..)
obj.CalculateSomethingImportant()
}
}

If it changes infrequently, you may just be better off using an
Initialize method or making the value a property and settings the value
after resolving the service.

IMyObject obj = kernel.Get<IMyService>();
obj.Initialize(5);
ovj.CalculateSomethingImportant() // Throw a NotInitializedException
if Initialize() hasn't been run first.

IMyObject obj = kernel.Get<IMyService>();
obj.RequiredProperty = 5;
obj.CalculateSomethingImportant() // Throw a
NotInitializatedException if RequiredProperty hasn't been set.

Regards,

Ben

Tod Gentille

unread,
Oct 23, 2009, 5:17:24 PM10/23/09
to nin...@googlegroups.com
Ben,
Thanks. I was thinking of asking a second question of should I even Inject
for this, so thanks for your opinion. Since I'm just learning I may be
getting a little lost in the woods and losing sight of my original purpose
here. The variable does change during the life of the application, but only
once, and very near to instantiation, but it is the result of user
interaction. The app starts and the user has to hit "Connect". Then the app
can fully initialize and do its thing.
However, I also liked your final suggestion, where I can use Ninject like a
Service Locator and have it give me back an invariant version of the class.
I avoided this type of initialization originally because I wanted the class
to be invariant but of course all I did was move the invariance to the class
that uses this one. So I think I'll rework it.

One last thing, I was just looking through the forum and there used to be a
syntax like
Get<SomeImpl>().WithArgument(someArg). Is that syntax gone? I don't know how
it worked if the constructor took more than one argument but the thing I
liked about it was you just passed the value for the argument not a "string"
name to identify the parameter.


Thanks Again,

Tod

Ben Ellis

unread,
Oct 23, 2009, 6:13:42 PM10/23/09
to nin...@googlegroups.com
Tod,

As I said, I don't really use the With.ConstructorArgument stuff.
But looking at 1.0 I don't think this works how you think. The
With.Parameters.ConstructorArguments(object arguments) takes an object and
will map each property in that object to an argument in the constrcutor.
e.g.

kernel.Get<IMyServiceClass>(With.Parameters.ConstructorArguments(new
() { param1 = 1, param2 = 5 })

This would create an annoymous class that has two properties param1
and param2. So you still require the name of the arguments.

This is not in Ninject 2.0 though the method could probably be added
quite easily using the same code from the Ninject 1.0 repository.

Tod Gentille

unread,
Oct 23, 2009, 10:01:52 PM10/23/09
to nin...@googlegroups.com
I went back looking for the example and I think I must have misread it. All
the examples I found did name the parameters. I'm going to either new this
class up manually, or modify it to use the initialization technique you
first mentioned.

I just finished refactoring my main presenter class to use Ninject 2.0. It's
both strange and wonderful to write a constructor that takes a large handful
of parameters, then hit SHIFT-F12 and realize there's no direct code that
calls the constructor. You can change the signature all you want and never
break anything!
Reply all
Reply to author
Forward
0 new messages