使用unity解析具有多个构造函数的实例
我想使用unity创建一个类的实例,其中类有两个具有相同参数数量的构造函数。
这是实例化:
_unityContainer.Resolve(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile));
以下是构造函数:
public GradeType(string gradeTypeStringFromXmlFile) { _gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile; } public GradeType(Enum.GradeType gradeType) { _gradeType = gradeType; }
如果我尝试这样做,我得到一个例外,说明类型GradeType有多个长度为1的构造函数。无法消除歧义 。
我可以在一个构造函数上设置属性[InjectionConstructor]以使其与一个一起工作,但是我不能使用另一个构造函数创建一个具有unity的实例。
是否有一些方法让多个构造函数具有相同数量的参数并仍然使用unity来创建实例?
是的,可以告诉Unity应该使用哪个构造函数,但只有在使用InjectionConstructor
注册类型时才能执行此操作。 如果你想使用两个构造函数,它甚至会很复杂,因为你必须在注册时命名注册并使用该名称。
使用Unity版本2.1.505构建的示例:
var continer = new UnityContainer(); continer.RegisterType("stringConstructor", new InjectionConstructor(typeof(string))); continer.RegisterType("enumConstructor", new InjectionConstructor(typeof(EnumGradeType))); IGradeType stringGradeType = continer.Resolve("stringContructor" , new DependencyOverride(typeof(string), "some string")); IGradeType enumGradeType = continer.Resolve ("enumConstructor", new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value));
使用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扫描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( new InjectionConstructor( typeof(ConstructorArgs) )); var args1 = new StringArg(gradeTypeStringFromXmlFile); // string IGradeType gradeType1 = _unityContainer.Resolve( new ResolverOverride[]{new ParameterOverride("args", args1)}); var args2 = new EnumArg(gradeType); // enum IGradeType gradeType2 = _unityContainer.Resolve ( new ResolverOverride[]{new ParameterOverride("args", args2)});
如果您计划在迭代中重复解析您的类型,那么这种方法可能并不理想,因为Reflection会带来性能损失。
删除一个构造函数,并将字符串转换为枚举,反之亦然,然后使用容器解析。