c# - 使用泛型时不注入属性(PropertiesAutowired)
问题描述
首先,让我们看一下代码:
using System;
using Autofac;
namespace PropertyInjectionAutofacPoC
{
public interface IInterfaceA { }
public interface IInterfaceB
{
IInterfaceA ClassA { get; set; }
}
public class ClassA : IInterfaceA { }
public class ClassB : IInterfaceB
{
public IInterfaceA ClassA { get; set; } // this is injected properly //
}
public class Z { }
public interface IInterfaceC<T> { }
public interface IInterfaceD<T>
{
IInterfaceA ClassA { get; set; }
IInterfaceC<T> ClassC { get; set; }
}
public interface IInterfaceCZ : IInterfaceC<Z> { }
public abstract class ClassD<T> : IInterfaceD<T>
{
public IInterfaceA ClassA { get; set; } // this is not injected, it's always null //
public IInterfaceC<T> ClassC { get; set; } // this is not injected, it's always null //
}
public abstract class ClassC<T> : IInterfaceC<T> { }
public sealed class ClassCZ : ClassC<Z>, IInterfaceCZ { }
public interface IRepositoryZ : IInterfaceD<Z> { }
public sealed class RepositoryZ : ClassD<Z>, IRepositoryZ { }
internal class Program
{
private static IContainer _container;
private static void Main()
{
try
{
RegisterServices();
// it works //
var a = _container.Resolve<IInterfaceB>();
// it doesn't work //
var b = _container.Resolve<IRepositoryZ>(); // ClassC property is null
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
DisposeServices();
}
}
private static void RegisterServices()
{
var builder = new ContainerBuilder();
builder.RegisterType<ClassA>().As<IInterfaceA>();
builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired(); // works like a charm //
builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired(); // it doesn't work //
builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();
builder.RegisterType<RepositoryZ>().As<IRepositoryZ>();
_container = builder.Build();
}
private static void DisposeServices()
{
if (_container != null &&
_container is IDisposable disposable)
disposable.Dispose();
}
}
}
如果我将所有内容都更改为构造函数,它会像魅力一样完美地工作,但是,在这里使用注入属性的主要思想是避免构造函数地狱。
在上面的代码片段中,有一些注释我提到了哪些有效,哪些无效。当没有使用泛型时,属性注入可以正常工作。
所以,我问你们,我在这里做错了什么以及我的代码缺少什么工作?
非常感谢!
解决方案
您在这里遇到的问题主要是关于您指定的位置PropertiesAutowired
与您正在解决的问题。
我已经RegisterServices
用一些额外的评论更新了你的方法。
private static void RegisterServices()
{
var builder = new ContainerBuilder();
builder.RegisterType<ClassA>().As<IInterfaceA>();
builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired();
// These registrations aren't really valid. You would never be able to
// resolve IInterfaceC<> or IInterfaceD<>, because they are abstract classes, so cannot be constructed.
// You'll always get a NoConstructorsFoundException.
builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired();
builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();
// When I resolve IRepositoryZ, this is the registration that gets provided. So this is where you need PropertiesAutowired.
// Just because RepositoryZ derives from ClassD<Z> does not mean it inherits any of its component registration information,
// which I think is what you may have been expecting.
//
// However, the resolve of IRepositoryZ will now throw a NoConstructorFoundException, because when it goes to inject IInterfaceC<Z>
// onto the property, it hits the invalid registration problem above.
builder.RegisterType<RepositoryZ>().As<IRepositoryZ>().PropertiesAutowired();
_container = builder.Build();
}
从根本上说,我认为您可能需要重新调整一些通用类与具体类继承。我认为没有一种直接的方法可以像您在此处尝试做的那样,通过具体的注册来提供通用服务。
推荐阅读
- dialogflow-es - 使用对话流聊天机器人,Slack 中是否提供“Google 上的操作”?
- mongodb - 嵌套字段 2 级别上的 Mongodb 聚合
- powershell - 获取 WinEvent 脚本
- .net - Wix BootStrapper exe无法在客户端机器上运行
- python - 无法连接到远程 Jupyter 笔记本
- powershell - 如何将程序集加载到 Powershell 的全局范围内?
- windows - Windows 性能记录器收集堆快照时出错。错误代码:0x80070032
- javascript - 如何使用数据加载器?
- docker - npm 库无法在 GitLab CI 中安装
- c# - 在 C# 中存储一些不可变和高度访问的数据的最佳方法是什么?