Конструктор Аргументы Enums и Magic Strings - PullRequest
3 голосов
/ 07 июля 2011

Я работаю над своим приложением c # .net и использую шаблон IoC / DI, используя Ninject, теперь у Ninject есть класс с именем ConstructorArgument, который принимает два аргумента (argName, argValue).

Так что мне нужнопередавать статическое argName как-то так

new ConstructorArgument("strVar","")

передача жестко закодированной строки не кажется хорошим вариантом.

Итак, я хочу создать что-то вроде динамического перечисления, используя отражение для аргументов конструктора, поэтому мне не нужно передавать жестко закодированные строки.

Пожалуйста, проведите меня через этот процесс или предложите мне что-то еще для достиженияэто.

Ответы [ 3 ]

3 голосов
/ 07 июля 2011

как динамические перечисления

Такой конструкции нет в наличии.Если вы действительно ненавидите строки, вы можете написать некое лямбда-выражение дерева выражений (то есть, однако, () => new Foo(strVal: "") или () => new Foo("") - что a: много работы, а b: не будетработать хорошо, если контейнер предоставляет другие параметры.

Если честно, это не проблема, особенно если именованные аргументы означают, что имена параметров должны рассматриваться как контракт.просто используйте строку. Если вас это беспокоит, убедитесь, что вы описали сценарий в модульном тесте, чтобы заранее узнать, изменился ли он.

2 голосов
/ 07 июля 2011

Я согласен с позицией @Mark Gravell, за исключением того, что обфускаторы могут переименовывать параметры для не-public ctors, поэтому рекомендации не применимы в этом конкретном случае, поэтому в некоторых случаях вам нужно нажать на [Obfuscation] на параметр, чтобы сохранить имя в некоторых случаях.

Но я построил такую ​​ерунду, которая отвечала бы на ваш вопрос. Пожалуйста, не используйте это, поскольку я сожалею, что пишу это!

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 ) );
    }
}

Что работает так:

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 );
    }
}
0 голосов
/ 20 февраля 2013

Я реализовал это:

    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();
    }

Это без LINQ, но это хорошая отправная точка, чтобы понять, как это работает.

...