为何Autofac无法实例化含泛型接口参数的Consumer类?
我使用Autofac实现依赖注入,定义了泛型接口IStateMachine<TState, TTrigger>和它的实现类ConcreteStateMachine,注册代码如下:
builder.RegisterType<ConcreteStateMachine>().As<IStateMachine<MachineState, Trigger>>();
Consumer类的构造函数依赖IStateMachine<MachineState, Trigger>,但调用container.Resolve<Consumer>()时抛出空引用异常,错误信息如下:
Unhandled exception. Autofac.Core.DependencyResolutionException: An exception was thrown while activating Consumer. ---> Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor(IStateMachine`2[MachineState,Trigger])' on type 'Consumer'. ---> System.NullReferenceException: Object reference not set to an instance of an object.
测试发现直接调用container.Resolve<IStateMachine<MachineState, Trigger>>()能正常获取实例,但Autofac无法将其注入到Consumer中。完整代码如下:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using Autofac; using Stateless; public class Program { public static void Main() { var builder = new ContainerBuilder(); builder.RegisterType<Consumer>() .InstancePerLifetimeScope(); builder.RegisterType<ConcreteStateMachine>() .As<IStateMachine<MachineState, Trigger>>() .InstancePerLifetimeScope(); var container = builder.Build(); using (var scope = container.BeginLifetimeScope()) { var consumer = scope.Resolve<Consumer>(); consumer.TurnOn(); consumer.GetData(); consumer.TurnOff(); } } } public class Consumer { protected IStateMachine<MachineState, Trigger> Machine; public Consumer(IStateMachine<MachineState, Trigger> machine) { Machine = machine; Machine.Register(MachineState.Off, () => Debug.WriteLine("State Off")); Machine.Register(MachineState.On, () => Debug.WriteLine("State On")); } public List<string> GetData() { if (!Machine.IsInState(MachineState.On)) throw new InvalidOperationException("Can't GetData when machine is off!"); Debug.WriteLine("Getting Data"); return new List<String> {"Data", "Data", "Data"}; } public void TurnOn() { Machine.Fire(Trigger.TurnOn); } public void TurnOff() { Machine.Fire(Trigger.TurnOff); } } public class ConcreteStateMachine : IStateMachine<MachineState, Trigger> { protected StateMachine<MachineState, Trigger> Machine; public MachineState CurrentState { get; set; } public void Fire(Trigger trigger) { Machine.Fire(trigger); } public async Task FireAsync(Trigger trigger) { await Machine.FireAsync(trigger); } public bool IsInState(MachineState state) { return Machine.IsInState(state); } public void Register(MachineState state, Action callback) { Machine.Configure(state) .OnEntry(() => callback.Invoke()); } public void RegisterAsync(MachineState state, Func<Task> callback) { Machine.Configure(state) .OnEntryAsync(async () => await callback.Invoke()); } public void Start() { ConfigureMachine(); Machine.Activate(); } protected void ConfigureMachine() { Machine = new StateMachine<MachineState, Trigger>(MachineState.Off); Machine.Configure(MachineState.Off) .Permit(Trigger.TurnOn, MachineState.On); Machine.Configure(MachineState.On) .Permit(Trigger.TurnOff, MachineState.Off); } } public interface IStateMachine<TState, TTrigger> { TState CurrentState { get; set; } bool IsInState(TState state); void Fire(TTrigger trigger); Task FireAsync(TTrigger trigger); void Start(); void Register(TState state, Action callback); void RegisterAsync(TState state, Func<Task> callback); } public enum MachineState { Off, On } public enum Trigger { TurnOff, TurnOn }
空引用异常并非Autofac注入失败导致,而是ConcreteStateMachine内部的Machine字段未初始化就被调用。
当Autofac创建ConcreteStateMachine实例后,会立即调用Consumer的构造函数,构造函数里直接调用Machine.Register()方法,但此时ConcreteStateMachine的Start()方法还未执行,ConfigureMachine()没被调用,Machine字段仍是null,因此触发空引用异常。
直接调用Resolve<IStateMachine<...>>()时,你可能在后续手动调用了Start()方法,但注入到Consumer时,构造函数提前调用了依赖实例的方法,导致问题暴露。
有两种可行的修复方式:
方式1:在ConcreteStateMachine构造函数中初始化状态机
修改ConcreteStateMachine,在构造函数里调用Start()完成状态机初始化:
public class ConcreteStateMachine : IStateMachine<MachineState, Trigger> { protected StateMachine<MachineState, Trigger> Machine; public MachineState CurrentState { get; set; } // 添加构造函数,自动初始化状态机 public ConcreteStateMachine() { Start(); } // 其余代码保持不变... }
方式2:延迟Consumer中的状态机注册逻辑
不在Consumer构造函数中调用Machine.Register(),而是新增初始化方法,在获取实例后手动调用:
public class Consumer { protected IStateMachine<MachineState, Trigger> Machine; public Consumer(IStateMachine<MachineState, Trigger> machine) { Machine = machine; // 移除构造函数中的Register调用 } // 添加初始化方法 public void Initialize() { Machine.Register(MachineState.Off, () => Debug.WriteLine("State Off")); Machine.Register(MachineState.On, () => Debug.WriteLine("State On")); Machine.Start(); // 确保状态机启动 } // 其余代码保持不变... }
同时修改Main方法中的调用逻辑:
using (var scope = container.BeginLifetimeScope()) { var consumer = scope.Resolve<Consumer>(); consumer.Initialize(); // 先执行初始化 consumer.TurnOn(); consumer.GetData(); consumer.TurnOff(); }
内容的提问来源于stack exchange,提问作者Lempface

