Can I use Ninject ConstructorArguments with strong naming?
Well, I don't know if "strong naming" is the right term, but what I want to do is as follows.
Currently I use ConstructorArgument like e.g. this:
public class Ninja
{
private readonly IWeapon _weapon;
private readonly string _name;
public Ninja(string name, IWeapon weapon)
{
_weapon = weapon;
_name = name;开发者_如何学编程
}
// ..more code..
}
public void SomeFunction()
{
var kernel = new StandardKernel();
kernel.Bind<IWeapon>().To<Sword>();
var ninja = kernel.Get<Ninja>(new ConstructorArgument("name", "Lee"));
}
Now, if I rename the parameter "name" (e.g. using ReSharper) the ConstructorArgument won't update, and I will get a runtime error when creating the Ninja. To fix this I need to manually find all places I specify this parameter through a ConstructorArgument and update it. No good, and I'm doomed to fail at some point even though I have good test coverage. Renaming should be a cheap operation.
Is there any way I can make a reference to the parameter instead - such that it is updated when I rename the parameter?
If you can share more of what you're really trying to achieve, you'll get a better answer. In general, you dont want to be relying on passing a ConstructorArgument at all if that can be helped - it should be a last resort way of shoehorning a parameter value into the creation of a component you don't own and hence can rely on not being renamed [as] willy nilly during refactoring activities. So for normal code, if you can try to keep it to interfaces to make things unambiguous and not be relying on the names that's better.
Cant dig up an example right now but there's a pretty common idiom called static reflection. A supplied ConstructorArgument can match any parameter of that name across any of the constructors so static reflection isnt the most appropriate thing in this instance.
Hence the best that'll static reflection will probably allow you to achieve is something like:
var ninja = ninject.Get<Ninja>( ParamNamesOf(()=>new Ninja( "dummy", "dummy" )).First() );
The typical example you'll see is where one wants to extract the name of a property being accessed on an instance. This is a little different as it needs to work on a constructor invocation expression.
As for finding an appropriate lib that already has just that, exercise for the searcher :D (But I'd suggest finding a better way to express what you want to do that doesnt use ConstructorArgument
in preference to this approach anyway.)
As you already noticed, this approach is very fragile and should be avoided. Try a design were you don't need to add the name as a constructor argument. You could do this for instance:
public class Ninja
{
private readonly IWeapon _weapon;
public Ninja(IWeapon weapon)
{
_weapon = weapon;
}
public string Name { get; set; }
// ..more code..
}
public void SomeFunction()
{
var kernel = new StandardKernel();
kernel.Bind<IWeapon>().To<Sword>();
var ninja = ninject.Get<Ninja>();
ninja.Name = "Lee";
}
I hope this helps.
Yes you can.
I have imlemented this:
public string GiveConstuctorArgumentName(Type class, Type constructorArgument)
{
var cons = class.GetConstructors();
foreach (var constructorInfo in cons)
{
foreach (var consParameter in constructorInfo.GetParameters())
{
if (consParameter.ParameterType == constructorArgument)
{
return consParameter.Name;
}
}
}
throw new InstanceNotFoundException();
}
Its without LINQ, but its a good start point to understand how its work.
精彩评论