Разрешить экземпляр с несколькими конструкторами, использующими единство - программирование
Подтвердить что ты не робот

Разрешить экземпляр с несколькими конструкторами, использующими единство

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

Вот экземпляр:

_unityContainer.Resolve<IGradeType>(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile));

И вот конструкторы:

    public GradeType( string gradeTypeStringFromXmlFile)
    {
        _gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile;
    }

    public GradeType(Enum.GradeType gradeType)
    {
        _gradeType = gradeType;
    }

Если я попытаюсь сделать это, я получаю исключение: Тип GradeType имеет несколько конструкторов длиной 1. Невозможно устранить помехи.

Я могу установить атрибут [InjectionConstructor] над одним конструктором, чтобы он работал с ним, но тогда я не могу создать экземпляр с единством, используя другой конструктор.

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

4b9b3361

Ответ 1

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

Образец, построенный с Unity версии 2.1.505:

var continer = new UnityContainer();

continer.RegisterType<IGradeType, GradeType>("stringConstructor", 
    new InjectionConstructor(typeof(string)));

continer.RegisterType<IGradeType, GradeType>("enumConstructor",
    new InjectionConstructor(typeof(EnumGradeType)));

IGradeType stringGradeType = continer.Resolve<IGradeType>("stringContructor" , 
    new DependencyOverride(typeof(string), "some string"));

IGradeType enumGradeType = continer.Resolve<IGradeType>("enumConstructor", 
    new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value));

Ответ 2

Альтернативный вариант с использованием Reflection и Шаблон стратегии.

1) Создайте базовый класс для аргументов конструкторов

public abstract class ConstructorArgs
{
}

2) Создайте последовательность различных классов конкретных аргументов:

public class StringArg : ConstructorArgs
{
    public string _gradeTypeStringFromXmlFile { get; set; }

    public StringArg (string gradeTypeStringFromXmlFile)
    {
        this._gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile ;
    }
}

public class EnumArg : ConstructorArgs
{
    public Enum.GradeType _gradeType { get; set; }

    public EnumArg (Enum.GradeType gradeType)
    {
        this._gradeType = gradeType ;
    }
}

3) Теперь в классе GradeType создайте методы, необходимые для Reflection. Параметр ParseArguments просматривает аргументы свойств и для каждого найденного, он копирует его значение в соответствующее свойство класса GradeType с помощью SetProperty. Поскольку он использует имя свойства для соответствия, важно сохранить одно и то же имя свойства как для класса GradeType, так и для конкретного ConstructorArgs:

        private void SetProperty(String propertyName, object value)
        {
            var property = this.GetType().GetProperty(propertyName);
            if (property != null)
                property.SetValue(this, value);
        }
        private void ParseArguments(ConstructorArgs args)
        {
            var properties = args.GetType().GetProperties();
            foreach (PropertyInfo propertyInfo in properties)
            {
                this.SetProperty(propertyInfo.Name, 
                   args.GetType().GetProperty(propertyInfo.Name).GetValue(args));
            }
        }

4) В классе GradeType создайте соответствующие свойства (помните, что вы должны использовать точно такие же имена и типы, которые вы использовали в конкретном ConstructorArgs, но вы можете использовать любые модификаторы доступа, которые вам нравятся)

    public string _gradeTypeStringFromXmlFile { get; set; }
    public Enum.GradeType _gradeType { get; set; }

5) Создайте конструктор для класса GradeType с параметром типа ConstructorArgs:

    public GradeType(ConstructorArgs args)
    {
        this.ParseArguments(args);
    }

6) Теперь вы можете зарегистрировать GradeType в Unity с помощью одного конструктора, но при его решении вы можете передавать разные типы:

    _unityContainer.RegisterType<IGradeType, GradeType>(
       new InjectionConstructor( typeof(ConstructorArgs) ));

    var args1 = new StringArg(gradeTypeStringFromXmlFile); // string
    IGradeType gradeType1 = _unityContainer.Resolve<IGradeType>(
       new ResolverOverride[]{new ParameterOverride("args", args1)});

    var args2 = new EnumArg(gradeType); // enum
    IGradeType gradeType2 = _unityContainer.Resolve<IGradeType>(
       new ResolverOverride[]{new ParameterOverride("args", args2)});

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

Ответ 3

Удалите один конструктор и введите строку в перечисление или наоборот, а затем разрешите использование контейнера.