Могу ли я использовать Ninject ConstructorArguments со строгими именами? - PullRequest
8 голосов
/ 14 апреля 2010

Ну, я не знаю, является ли термин "сильное наименование" правильным, но я хочу сделать следующее.

В настоящее время я использую ConstructorArgument, например, например. это:

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

Теперь, если я переименую параметр "name" (например, с помощью ReSharper), ConstructorArgument не будет обновляться, и я получу ошибку во время выполнения при создании ниндзя. Чтобы это исправить, мне нужно вручную найти все места, где я указываю этот параметр через ConstructorArgument, и обновить его. Ничего хорошего, и я обречен на провал в какой-то момент, хотя у меня хорошее тестовое покрытие. Переименование должно быть дешевой операцией.

Можно ли вместо этого сделать ссылку на параметр - чтобы он обновлялся при переименовании параметра?

Ответы [ 3 ]

5 голосов
/ 14 апреля 2010

Если вы сможете рассказать больше о том, чего вы действительно пытаетесь достичь, вы получите лучший ответ. В общем, вы вообще не хотите полагаться на передачу ConstructorArgument, если это может помочь - это должен быть последний способ вставить значение параметра в создание компонента, которым вы не владеете, и, следовательно, можете полагаться на быть переименованным [as] willy nilly во время рефакторинга. Так что для нормального кода, если вы можете попытаться сохранить его в интерфейсах, чтобы сделать вещи однозначными и не полагаться на имена, которые лучше.

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

Следовательно, лучшее, что статическое отражение, вероятно, позволит вам достичь, это что-то вроде:

var ninja = ninject.Get<Ninja>( ParamNamesOf(()=>new Ninja( "dummy", "dummy" )).First() );

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

Что касается поиска подходящей библиотеки, которая уже имеет именно это, выполните упражнение для поисковика: D (Но я бы посоветовал найти лучший способ выразить то, что вы хотите сделать, который не использует ConstructorArgument в предпочтении этому подходу в любом случае .)

4 голосов
/ 14 апреля 2010

Как вы уже заметили, этот подход очень хрупок и его следует избегать. Попробуйте дизайн, если вам не нужно добавлять имя в качестве аргумента конструктора. Вы можете сделать это, например:

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

Надеюсь, это поможет.

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, но хорошая отправная точка, чтобы понять, как это работает.

...