使用unity解析具有多个构造函数的实例

时间:2012-01-13 15:40:28

标签: c# unity-container ioc-container

我想使用unity创建一个类的实例,其中类有两个具有相同参数数量的构造函数。

这是实例化:

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

以下是构造函数:

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

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

如果我尝试这样做,我会得到一个例外,说明类型GradeType有多个长度为1的构造函数。无法消除歧义

我可以在一个构造函数上设置属性[InjectionConstructor]以使其与一个构造函数一起使用,但是我无法使用其他构造函数创建一个具有单元的实例。

是否有一些方法可以让多个构造函数具有相同数量的参数并仍然使用unity来创建实例?

3 个答案:

答案 0 :(得分:28)

是的,可以告诉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));

答案 1 :(得分:1)

使用反射并遵循Strategy Pattern的替代选项。

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扫描args中的属性,对于它找到的每个属性,它使用SetProperty将其值复制到GradeType的相应属性。由于它使用属性名称进行匹配,因此在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)使用类型为ConstructorArgs的参数为GradeType类创建构造函数:

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

6)现在您可以使用单个构造函数在Unity中注册GradeType,但在解析它时可以传入不同类型的参数:

    _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会带来性能损失。

答案 2 :(得分:-1)

删除一个构造函数,然后将字符串转换为枚举,反之亦然,然后使用容器解析。