You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Autofac实现WinForms UserControl等派生类的属性自动注入

实现方案

1. 中间件代码修正

你原有实现存在三个核心问题:

  • 管道阶段选择错误:ParameterSelection 阶段目标实例尚未构造完成,无法访问实例属性
  • 判断对象错误:context.Service 是Autofac的服务标识对象,不是解析出来的实例
  • 缺少递归扫描嵌套控件属性的逻辑

正确的中间件实现如下:

using System.Reflection;
using Autofac.Core.Resolving;
using Autofac.Core.Resolving.Pipeline;

public class AutofacUserControlPropertyInjectionMiddleware : IResolveMiddleware
{
    private static readonly List<Type> InjectTargetBaseTypes = new List<Type>
    {
        typeof(UserControl),
        typeof(BarItem)
    };

    public PipelinePhase Phase => PipelinePhase.Activation;

    public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
    {
        // 先执行后续管道逻辑,确保实例已经完成构造
        next(context);

        // 仅处理顶层Form实例的注入扫描
        if (context.Instance is Form topForm)
        {
            var processedInstances = new HashSet<object>();
            InjectRecursive(context, topForm, processedInstances);
        }
    }

    private static void InjectRecursive(ResolveRequestContext context, object instance, HashSet<object> processed)
    {
        if (instance == null || processed.Contains(instance))
            return;

        processed.Add(instance);

        // 先为当前实例注入容器中匹配的服务属性
        context.InjectProperties(instance);

        // 扫描所有公共可写属性
        var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanWrite && p.GetGetMethod() != null && p.GetSetMethod() != null);

        foreach (var prop in properties)
        {
            var propValue = prop.GetValue(instance);
            if (propValue == null)
                continue;

            // 判断属性类型是否属于需要注入的控件类型
            var propType = propValue.GetType();
            if (InjectTargetBaseTypes.Any(baseType => baseType.IsAssignableFrom(propType)))
            {
                // 递归处理子控件的属性注入
                InjectRecursive(context, propValue, processed);
            }
        }
    }
}

2. 注册中间件到Autofac容器

在容器构建时,将该中间件应用到所有顶层Form类型的注册项上即可:

var builder = new ContainerBuilder();

// 单个注册Form示例
builder.RegisterType<MyModalDialog>().AsSelf();

// 批量注册所有Form子类示例
// builder.RegisterAssemblyTypes(typeof(Program).Assembly)
//    .Where(t => typeof(Form).IsAssignableFrom(t))
//    .AsSelf();

// 为所有Form类型的注册项添加注入中间件
builder.RegisterCallback(registry =>
{
    foreach (var registration in registry.Registrations)
    {
        if (typeof(Form).IsAssignableFrom(registration.Activator.LimitType))
        {
            registration.PipelineBuilder.Use(new AutofacUserControlPropertyInjectionMiddleware());
        }
    }
});

var container = builder.Build();

3. 注意事项

  • 所有需要被扫描注入的UserControl、BarItem必须以公共可写属性的形式暴露在父控件/Form中
  • 递归逻辑加入了已处理实例的哈希集,避免嵌套控件互相引用导致的死循环
  • 控件默认构造函数完全保留,不影响Visual Studio窗体设计器的正常使用

内容的提问来源于stack exchange,提问作者void.pointer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:06:01