簡體   English   中英

為什么Autofac不能創建這個將泛型接口的非泛型實現作為構造函數參數的class?

[英]Why can Autofac not create this class that takes a non-generic implementation of a generic interface as a constructor parameter?

使用 Autofac 進行注射。

鑒於

interface IStateMachine<TState, TTrigger> { } 
class ConcreteStateMachine : IStateMachine<MachineState, Trigger> { }
builder.RegisterType<ConcreteStateMachine>().As<IStateMachine<MachineState, Trigger>>();
class Consumer { Consumer(IStateMachine<MachineState, Trigger> machine) { } }

為什么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.

完整的代碼設計示例: Autofac無狀態需要 nuget

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的實例。

正如在container.Resolve<IStateMachine<MachineState, Trigger>>()中正確提供了一個ConcreteStateMachine ,但 Autofac 似乎不知道如何將實例發送到Consumer

ConcreteStateMachineMachine字段未初始化,為null 所以它在NullReferenceException中失敗:

public void Register(MachineState state, Action callback)
{
    Machine.Configure(state)
        .OnEntry(() => callback.Invoke());
}

只是在創建人為示例時引入錯誤的情況......

我從未在 Consumer 的構造函數中調用 Machine.Start(),它在調用 Register 之前實例化內部 StateMachine,Register 調用底層 StateMachine 上的方法。 這導致在創建 Consumer 時拋出異常,實際上並不是 Autofac 配置問題。

對不起!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM