问题
I am working on my c# .net application and use implement IoC/DI pattern using Ninject, Now Ninject has a class named ConstructorArgument
which takes two arguments(argName,argValue).
So i need to pass static argName something like this
new ConstructorArgument("strVar","")
passing hardcoded string does not seems like a good option.
So i want to create something like dynamics enums using reflection for the constructor arguments, so i dont need to pass hardcoded strings.
Please guide me through this process or suggest me something else to achieve this.
回答1:
like dynamics enums
There is no such construct readily available. If you really hate the strings, you could write some kind of expression-tree lambda (i.e. () => new Foo(strVal: "")
or () => new Foo("")
, however - that a: is a lot of work, and b: won't work well if there are other parameters being provided by the container.
To be honest, this is a bit of a non-issue, especially since named arguments mean that parameter names should be treated as a contract. IMO, just use the string. If it worries you, make sure you cover the scenario in a unit test, so that you find out early if it changes.
回答2:
I agree with @Mark Gravell's stance, except that obfuscators can rename parameters for non-public
ctors so the advice doesn't apply in that specific case, so in some cases, you need to whack on a [Obfuscation]
on the parameter to preserve the name in some instances.
But I have built nonsense like this which would answer your question. Please don't use it as I regret writing it!
static class StaticReflection<TClass>
{
static string PublicConstructorParameterName<TParameter>()
{
return typeof( TClass ).GetConstructors( BindingFlags.Public | BindingFlags.Instance ).Single().GetParameters().Where( param => param.ParameterType == typeof( TParameter ) ).Single().Name;
}
internal static ConstructorArgument CreateConstructorArgument<TParameter>( TParameter value )
{
return new ConstructorArgument( PublicConstructorParameterName<TParameter>(), value );
}
internal static ConstructorArgument CreateConstructorArgument<TParameter>( Func<IContext, TParameter> argumentResolver )
{
return new ConstructorArgument( PublicConstructorParameterName<TParameter>(), context => (object)argumentResolver( context ) );
}
}
Which works like this:
public class StaticReflectionFacts
{
public class X2
{
}
public class X
{
public X( object param1, X2 param2 )
{
}
}
[Fact]
static void DeriveNinjectConstructorArgumentFromPublic()
{
var newArg = StaticReflection<X>.CreateConstructorArgument( new X2() );
Assert.Equal( "param2", newArg.Name );
}
}
回答3:
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.
来源:https://stackoverflow.com/questions/6607171/constructor-argument-enums-and-magic-strings