kirov-opensource / NAutowired

ASP.NET CORE Field Injection Implement
MIT License
77 stars 16 forks source link

HASH无法自动注册 #16

Closed qinqoushui closed 3 years ago

qinqoushui commented 3 years ago

在JAVA中,可以这样使用 @Autowired Map<String, DataBodyFormatter> formatters; 在DOTNETCORE中 [Autowired] public Dictionary<string, IDataBodyFormatterBase> FormatterDict { get; set; } 运行报错

NAutowired.Core.Exceptions.UnableResolveDependencyException:“Unable to resolve dependency System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Q.Protocol.Interfaces.IDataBodyFormatterBase, Q.Protocol, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]”

代码 如下

[Component]
    public class DataBodyFormatterFactory : IDataBodyFormatterFactory
    {

        [Autowired]
        public Dictionary<string, IDataBodyFormatterBase> FormatterDict { get; set; }
}

# 单元测试代码
[TestClass()]
    public class DataBodyFormatterFactoryTests
    {
 private readonly IConsoleHost consoleHost = ConsoleHost.CreateDefaultBuilder(new List<string> { "Q.Protocol" }).Build();

        [TestMethod()]
        public void getDataBodyFormatterTest()
        {
            IServiceCollection services = new ServiceCollection();

            var ServiceProvider = services.BuildServiceProvider();
           var x = consoleHost.GetService<DataBodyFormatterFactory>();
        }
}
FatTigerWang commented 3 years ago

如果你想要还原出Dictionary<string, IDataBodyFormatterBase>,你需要首先将Dictionary<string, IDataBodyFormatterBase>加到容器内,仅仅在DataBodyFormatterFactory上使用[Component]是不够的,因为没法在Dictionary类型增加[Component]特性,因此你可以新建类继承自Dictionary:

[Component]
public class CustomerDictionary:Dictionary {

}

更推荐的另一种做法是在Startup.cs:

services.AddScoped(serviceProvider =>
            {
               //创建实例 伪代码
                var instance = new Dictionary<string, IDataBodyFormatterBase>();
                return instance ;
            });
FatTigerWang commented 3 years ago

另外,也许你是想还原出实现IDataBodyFormatterBase实例,可以使用[Autowired(typeof(ImplementClass))]指定要还原出实现此接口的实例

qinqoushui commented 3 years ago

用您给出的方法没能实现,我的意思是搜索所有注册的实现了某个接口的类,放到工厂类下面注册。按照这个思路 ,我修改了您的源码

 private static void ResolveDependencyTree(IServiceProvider serviceProvider, InstanceScopeModel instanceScopeModel)
        {
            foreach (var memberInfo in instanceScopeModel.Instance.GetType().GetFullMembers())
            {
                var customeAttribute = memberInfo.GetCustomAttribute(autowiredAttributeType, false);

                var memberType = memberInfo.GetRealType();
                object instance = null;
                if (memberType.GetInterface("IDictionary") != null && memberType.GenericTypeArguments[0].Name == nameof(String))
                {
                    //字典类,查找所有实现并加入字典 
                    instance = Activator.CreateInstance(memberType);
                    memberInfo.SetValue(instanceScopeModel.Instance, instance);
                    ResolveDependency4Dictionary(serviceProvider, new InstanceScopeModel() { Instance = instance }, memberType);
                }
                else
                {
....
                }
 //构建下一个节点
                var nextInstanceScopeModel = new InstanceScopeModel
                {
                    Instance = instance,
                    ParentInstanceScope = instanceScopeModel
                };
                //递归注入的属性是否有其它依赖
                ResolveDependencyTree(serviceProvider, nextInstanceScopeModel);
}
 private static void ResolveDependency4Dictionary(IServiceProvider serviceProvider, InstanceScopeModel instanceScopeModel, Type type)
        {
            var implements = serviceProvider.GetServices(type.GenericTypeArguments[1]);
            //反射调用方法添加
            var addMethod = type.GetMethod("Add");
            foreach (var r in implements)
            {
                addMethod.Invoke(instanceScopeModel.Instance, new object[] { r.GetType().Name, r });
                var nextInstanceScopeModel = new InstanceScopeModel
                {
                    Instance = r,
                    ParentInstanceScope = instanceScopeModel
                };
                //递归注入的属性是否有其它依赖
                ResolveDependencyTree(serviceProvider, nextInstanceScopeModel);
            }
        }
FatTigerWang commented 3 years ago

可以作为新功能提供,NETCore的默认构造函数还原支持IList<Interface>这种方式进行还原