Unity - 为啥 Resolve(ParameterOverride[]) 不使用预期的构造函数?

Posted

技术标签:

【中文标题】Unity - 为啥 Resolve(ParameterOverride[]) 不使用预期的构造函数?【英文标题】:Unity - Why isn't Resolve(ParameterOverride[]) using the expected constructor?Unity - 为什么 Resolve(ParameterOverride[]) 不使用预期的构造函数? 【发布时间】:2022-01-13 18:09:10 【问题描述】:

我想将 IoD 与实现接口并具有带参数的构造函数的类一起使用。

界面:

    public interface IUsefulClass
    
        string InterestingInfo  get; set; 
        string RelevantStuff  get; set; 
    

两个简单的属性,没什么好说的。

班级:

    public class UsefulClass : IUsefulClass
    
        public string InterestingInfo  get; set; 

        public string RelevantStuff  get; set; 

        public UsefulClass()
        
        

        public UsefulClass(string p_strInterestingInfo)
        
            InterestingInfo = p_strInterestingInfo;
        

        public UsefulClass (string p_strInterestingInfo, string p_strRelevantStuff)
        
            InterestingInfo = p_strInterestingInfo;
            RelevantStuff = p_strRelevantStuff;
        
    

它有几个不同的构造函数,每个构造函数都以自己的方式设置属性。

另一个类的调用:

        public void HereGoes()
        
            IUnityContainer z_ucoContainer = new UnityContainer();

            z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>();

            IUsefulClass z_objUsefulButEmpty = z_ucoContainer.Resolve<IUsefulClass>();
            IUsefulClass z_objUsefulAndInteresting = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride("p_strInterestingInfo", "This is interesting information"));
            IUsefulClass z_objUsefulAndInterestingToo = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride[]  new ParameterOverride("p_strInterestingInfo", "This is very interesting information") );
            IUsefulClass z_objUsefulInterestingAndRelevant = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride("p_strInterestingInfo", "This is quite interesting information"), new ParameterOverride("p_strRelevantStuff", "More relevant stuff here"));
            IUsefulClass z_objUsefulInterestingAndRelevantAsWell = z_ucoContainer.Resolve<IUsefulClass>(new ParameterOverride[]  new ParameterOverride("p_strInterestingInfo", "This is possibly the most interesting information"), new ParameterOverride("p_strRelevantStuff", "Look for relevant stuff there") );
        

在测试和调试时,我发现所有五个变量在两个属性中都有null

再调试一番,发现每个Resolve()都调用了无参数构造函数。

我尝试删除上述构造函数(当然还有设置 z_objUsefulButEmpty 的代码行):我收到 Unity.ResolutionFailedException 消息“解决失败并出现错误:无法为 RegMat_VM.Infrastructure.UsefulClass 选择构造函数” .

我看了又看(here 和 there 以及其他地方),但找不到我做错了什么。我怎样才能让它正常工作?

【问题讨论】:

【参考方案1】:

解决办法是这样调用:

IUnityContainer z_ucoContainer = new UnityContainer();
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>();
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>("stringConstructor",new InjectionConstructor (typeof(string)));
z_ucoContainer.RegisterType<IUsefulClass, UsefulClass>("string2Constructor", new InjectionConstructor (typeof(string), typeof(string)));
IUsefulClass z_objUsefulButEmpty = z_ucoContainer.Resolve<IUsefulClass>();
IUsefulClass z_objUsefulAndInteresting = z_ucoContainer.Resolve<IUsefulClass>("stringConstructor",new ParameterOverride("p_strInterestingInfo", "This is interesting information"));
IUsefulClass z_objUsefulAndInterestingToo = z_ucoContainer.Resolve<IUsefulClass>("stringConstructor",new ParameterOverride[]  new ParameterOverride("p_strInterestingInfo", "This is very interesting information") );
IUsefulClass z_objUsefulInterestingAndRelevant = z_ucoContainer.Resolve<IUsefulClass>("string2Constructor",new ParameterOverride("p_strInterestingInfo", "This is quite interesting information"), new ParameterOverride("p_strRelevantStuff", "More relevant stuff here"));
IUsefulClass z_objUsefulInterestingAndRelevantAsWell = z_ucoContainer.Resolve<IUsefulClass>("string2Constructor",new ParameterOverride[]  new ParameterOverride("p_strInterestingInfo", "This is possibly the most interesting information"), new ParameterOverride("p_strRelevantStuff", "Look for relevant stuff there") );

这涉及到构造注入的知识。

当有多个构造函数时,可以使用InjectionConstructorAttribute来装饰你唯一需要的构造函数。

当您需要同时使用multiple constructors时,您需要命名它们并在解析时使用该名称

有关命名构造函数的更一般用法,请参见下文:

using System;
using System.Collections.Generic;
using Unity;
using Unity.Injection;
using Unity.Resolution;

namespace ConsoleApp1 
    class Program 
        static void Main (string[] args) 
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IPeople, Swordsman>(new InjectionConstructor());//Unnamed default registration, the following default registration will overwrite the previous one
            container.RegisterType<IPeople, Witch>("Witch");//Named registration

            IPeople people=container.Resolve<IPeople>();//Resolve default objects           
            IPeople _witch =container.Resolve<IPeople>("Witch");//Specify the name resolution object

            IEnumerable<IPeople> peoples=container.ResolveAll<IPeople>();//Get all registered named objects of IPeople in the container
            
            people.ClassName = people.GetType().ToString();
            _witch.ClassName = _witch.GetType().ToString();
            var info1= people.ShowInfo();
            var info2= _witch.ShowInfo();

            foreach (var item in peoples)
                
                item.ClassName = item.GetType().ToString();
                Console.WriteLine(item.ShowInfo());
                
            Console.WriteLine(info1);
            Console.WriteLine(info2);
            //Dealing with the case of multiple constructors:
            container.RegisterType<IPeople, Swordsman>("SString",new InjectionConstructor(typeof(string)));
            container.RegisterType<IPeople, Swordsman>("TString", new InjectionConstructor(typeof(string), typeof(string)));

            var people2=container.Resolve<IPeople>("SString",new ParameterOverride("o" ,"hello"));
            IPeople people3=container.Resolve<IPeople>("TString",new ParameterOverride ("o", "hello"),new ParameterOverride ("g", "world"));
            Console.WriteLine(people2.ClassName);
            Console.WriteLine(people3.ClassName + people3.ClassAge);
            
            Console.ReadLine();
            
        

    //People interface
    public interface IPeople 
        string ClassName 
            get; set;
            
        string ClassAge 
            get; set;
            
        string ShowInfo ();
        

    //Witch
    public class Witch : IPeople 
        public string ClassName 
            get; set;
            
        public string ClassAge 
            get; set;
            
        public string ShowInfo () 
            return string.Format("Witch:0", ClassName);
            
        

    //Swordsman 
    public class Swordsman : IPeople 
        public string ClassName 
            get; set;
            
        public string ClassAge 
            get;set;
            
        public string ShowInfo () 
            return string.Format("Swordsman:0", ClassName);
            
        
        public Swordsman (string o) 
            ClassName = o;
            
        //[InjectionConstructor]
        public Swordsman () 
            
        
        public Swordsman (string o, string g) 
            ClassName = o;
            ClassAge = g;
            
        
    

输出:

【讨论】:

@Jean-DavidLanz 谢谢,一切都是为了更好地服务客户。

以上是关于Unity - 为啥 Resolve(ParameterOverride[]) 不使用预期的构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

获取Resolve unity容器的界面

使用Unity依赖注入的时候,最上层的类是Resolve还是New的问题

为啥我们需要返回一个 promise resolve?

为啥链接到 Promise.resolve() 的 .then() 允许重新分配 const 声明?

为啥 Promise 构造函数需要一个在完成时调用 'resolve' 的函数,但 'then' 不需要 - 它返回一个值?

AIOHTTP with Graphql: TypeError: __init__() got an unexpected keyword argument 'resolve'。为啥会出现这个问题?