如何解决Autofac循环依赖?

Ami*_*mit 4 c# circular-dependency autofac

最近开始使用 autofac,我遇到了循环依赖问题,在使用 Unity 时我已经克服了这个问题。这是我的代码:

 void Main()
 {
    var builder = new ContainerBuilder();

    // 1) Every class needs logger
    // 2) Logger needs AppSettingsProvider which needs AppEnvironmentProvider
    // 3) Listener needs AppSettingsProvider which needs AppEnvironmentProvider

    builder.RegisterType<Logger>().As<ILogger>().SingleInstance();
    builder.RegisterType<AppSettingsProvider>().As<IAppSettingsProvider>().SingleInstance();
    builder.RegisterType<AppEnvironmentProvider>().As<IAppEnvironmentProvider>().SingleInstance();

    builder.RegisterType<Listener>().As<IListener>().SingleInstance();

    var container = builder.Build();

    var listener = container.Resolve<IListener>();
    listener.Do();

 }

 public interface IListener
 { 
    string Do();
 }

 public class Listener : IListener
 { 
    IAppSettingsProvider appSettingsProvider;
    public Listener(IAppSettingsProvider appSettingsProvider)
    {
        // this class needs IAppSettingsProvider to get some settings
        // but not actually used on this example.
        this.appSettingsProvider = appSettingsProvider;
    }
    public string Do()
    {
        return "doing something";
    }
 }

 public interface ILogger
 { 
    void Log(string message);
 }

 public class Logger : ILogger
 {
    IAppSettingsProvider appSettingsProvider;
    public Logger(IAppSettingsProvider appSettingsProvider)
    {
        this.appSettingsProvider = appSettingsProvider;
    }

    public void Log(string message)
    {
        // simplified
        if (this.appSettingsProvider.GetSettings())
        {
            Console.WriteLine(message);
        }
    }
 }

 public interface IAppSettingsProvider
 { 
    // will return a class, here simplified to bool
    bool GetSettings();
 }

 public class AppSettingsProvider : IAppSettingsProvider
 { 
    ILogger logger;
    public AppSettingsProvider(ILogger logger)
    {
        this.logger = logger;
    }

    public bool GetSettings()
    {
        this.logger.Log("Getting app settings");

        return true;
    }
 }


 public interface IAppEnvironmentProvider
 { 
    string GetEnvironment();
 }

 public class AppEnvironmentProvider : IAppEnvironmentProvider
 { 
    ILogger logger;
    public AppEnvironmentProvider(ILogger logger)
    {
        this.logger = logger;
    }
    public string GetEnvironment()
    {
        this.logger.Log("returning current environment");

        return "dev";
    }
 }
Run Code Online (Sandbox Code Playgroud)

任何有关解决此问题的指示都会有所帮助。

小智 5

您在这里有 2 个选择:

  1. 使用属性注入
  2. 使用工厂(这可能会与您的工厂产生强烈的依赖关系)

这是使用属性注入的示例:

    static void Main()
    {
        var builder = new ContainerBuilder();

        // 1) Every class needs logger
        // 2) Logger needs AppSettingsProvider which needs AppEnvironmentProvider
        // 3) Listener needs AppSettingsProvider which needs AppEnvironmentProvider

        builder.RegisterType<Logger>().As<ILogger>().SingleInstance();

        builder.RegisterType<AppSettingsProvider>()
            .As<IAppSettingsProvider>()
            .SingleInstance()
            .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

        builder.RegisterType<AppEnvironmentProvider>().As<IAppEnvironmentProvider>().SingleInstance();

        builder.RegisterType<Listener>().As<IListener>().SingleInstance();

        var container = builder.Build();

        var listener = container.Resolve<IListener>();

        Console.WriteLine(listener.Do());

        Console.Read();

    }

    public interface IListener
    {
        string Do();
    }

    public class Listener : IListener
    {
        IAppSettingsProvider appSettingsProvider;
        public Listener(IAppSettingsProvider appSettingsProvider)
        {
            // this class needs IAppSettingsProvider to get some settings
            // but not actually used on this example.
            this.appSettingsProvider = appSettingsProvider;
        }
        public string Do()
        {
            return "doing something using circular Dependency";
        }
    }

    public interface ILogger
    {
        void Log(string message);
    }

    public class Logger : ILogger
    {
        IAppSettingsProvider appSettingsProvider;
        public Logger(IAppSettingsProvider appSettingsProvider)
        {
            this.appSettingsProvider = appSettingsProvider;
        }

        public void Log(string message)
        {
            // simplified
            if (this.appSettingsProvider.GetSettings())
            {
                Console.WriteLine(message);
            }
        }
    }

    public interface IAppSettingsProvider
    {
        // will return a class, here simplified to bool
        bool GetSettings();
    }

    public class AppSettingsProvider : IAppSettingsProvider
    {
        ILogger logger;
        public AppSettingsProvider()
        {

        }

        public ILogger Logger { get; set; }

        public bool GetSettings()
        {
            Logger.Log("Getting app settings");

            return true;
        }
    }


    public interface IAppEnvironmentProvider
    {
        string GetEnvironment();
    }

    public class AppEnvironmentProvider : IAppEnvironmentProvider
    {
        ILogger logger;
        public AppEnvironmentProvider(ILogger logger)
        {
            this.logger = logger;
        }
        public string GetEnvironment()
        {
            this.logger.Log("returning current environment");

            return "dev";
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是 Autofac 建议: Autofac 参考


Kib*_*ria 5

Lazy<ILogger>另一种解决方法是在依赖服务的构造函数中使用。

public class AppSettingsProvider : IAppSettingsProvider
{
    Lazy<ILogger> logger;
    public AppSettingsProvider(Lazy<ILogger> logger)
    {
        this.logger = logger;
    }
    public bool GetSettings()
    {
        this.logger.Value.Log("Getting app settings");
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)