Могу ли я использовать Ninject ConstructorArguments со строгими именами?
Ну, я не знаю, является ли термин "сильное наименование" правильным, но я хочу сделать следующее.
В настоящее время я использую 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 ответа
Если вы сможете рассказать больше о том, чего вы действительно пытаетесь достичь, вы получите лучший ответ. В общем, вы вообще не хотите полагаться на передачу ConstructorArgument, если это может помочь - это должен быть последний способ вставить значение параметра в создание компонента, которым вы не владеете, и, следовательно, можете полагаться на быть переименованным [as] willy nilly во время рефакторинга. Так что для нормального кода, если вы можете попытаться сохранить его в интерфейсах, чтобы сделать вещи однозначными и не полагаться на имена, которые лучше.
Не могу найти пример прямо сейчас, но есть довольно распространенная идиома, называемая статическим отражением. Предоставленный ConstructorArgument может соответствовать любому параметру с таким именем в любом из конструкторов, поэтому статическое отражение не является наиболее подходящей вещью в этом случае.
Следовательно, лучшее, что статическое отражение, вероятно, позволит вам достичь, это что-то вроде:
var ninja = ninject.Get<Ninja>( ParamNamesOf(()=>new Ninja( "dummy", "dummy" )).First() );
Типичный пример, который вы увидите, - это когда вы хотите извлечь имя свойства, к которому обращаются в экземпляре. Это немного отличается, так как нужно работать с выражением вызова конструктора.
Что касается поиска подходящей библиотеки, которая уже имеет именно это, выполните упражнение для поисковика:D (Но я бы посоветовал найти лучший способ выразить то, что вы хотите сделать, не используя ConstructorArgument
в любом случае предпочтение этому подходу.)
Как вы уже заметили, этот подход очень хрупкий и его следует избегать. Попробуйте дизайн, если вам не нужно добавлять имя в качестве аргумента конструктора. Вы могли бы сделать это, например:
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";
}
Надеюсь, это поможет.
Да, ты можешь.
Я высказал это:
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, но это хорошая отправная точка, чтобы понять, как это работает.