使用静态记录器,静态助手类进行依赖注入

时间:2009-08-18 12:20:35

标签: c# unit-testing static dependency-injection

我有一个静态类,它调用静态Logger类,

e.g

static class DoesStuffStatic
{
  public static void DoStuff()
  {
    try
    {
      //something
    }
    catch(Exception e)
    {
      //do stuff; 
      Logger.Log(e);
    }
  }
}

static class Logger
{
  public static void Log(Exception e)
  {
     //do stuff here
  }
}

如何将Logger注入静态类?

注意:我已阅读Dependency Injection in .NET with examples?,但这似乎使用了实例记录器。

4 个答案:

答案 0 :(得分:32)

您无法注入静态记录器。您必须将其更改为实例记录器(如果可以),或将其包装在实例记录器中(将调用静态)。同样很难向静态类注入任何东西(因为你不以任何方式控制静态构造函数) - 这就是为什么我倾向于将我想要注入的所有对象作为参数传递。

答案 1 :(得分:23)

不一定如此。只要您的静态记录器公开以下方法:

  • 注入您想要注入的课程,或
  • 在运行之前在适当的方法调用中注入DI容器(比如asp.net global.asax Application_Start方法),那么你应该没问题。

这是一个例子。请参考以下课程:DI:

 public class Logger : ILogger
    {
        public void Log(string stringToLog)
        {
           Console.WriteLine(stringToLog);
        }
    }

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

这是我们需要记录器的静态类:

public static class SomeStaticClass
    {
        private static IKernel _diContainer;
        private static ILogger _logger;

        public static void Init(IKernel dIcontainer)
        {
            _diContainer = dIcontainer;
            _logger = _diContainer.Get<ILogger>();
        }


        public static void Log(string stringToLog)
        {
            _logger.Log(stringToLog);
        }


    }

现在,在您的应用程序的全局启动中(在本例中,在我的global.asax.cs中),您可以实例化您的DI容器,然后将其交给您的静态类。

public class Global : Ninject.Web.NinjectHttpApplication
    {

        protected override IKernel CreateKernel()
        {
            return Container;
        }


        static IKernel Container
        {
            get
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<ILogger>().To<Logger>();
                return standardKernel;
            }

        }

        void Application_Start(object sender, EventArgs e)
        {
            SomeStaticClass.Init(Container);
            SomeStaticClass.Log("Dependency Injection with Statics is totally possible");

        }

并且presto!您现在已经在静态类中使用DI运行了。

希望有人帮助。我正在重新使用一个使用大量静态类的应用程序,我们已经成功使用了一段时间了。

答案 2 :(得分:1)

这是“注入”静态记录器功能的一种非常简单的方法。

public static class Logger
{
    private static Action<string, Exception> _logError;
    public static bool Initialised;

    public static void InitLogger(Action<string, Exception, bool> logError)
    {
        if(logError == null) return;
        _logError = logError
        Initialised = true;
    }

    public static void LogError(string msg, Exception e = null)
    {
        if (_logError != null)
        {
            try
            {
                _logError.Invoke(msg, e);
            }
            catch (Exception){}
        }
        else
        {
            Debug.WriteLine($"LogError() Msg: {msg} Exception: {e}");
        }
    }
}

public class MainViewModel
{
    public MainViewModel()
    {
        //Inject the logger so we can call it globally from anywhere in the project
        Logger.InitLogger(LogError);
    }
    public void LogError(string msg, Exception e = null)
    {
        //Implementation of logger
    }
}

答案 3 :(得分:0)

我不确定Logger的工作原理,但通常您可以使用 RequestService 来获取您的实例。例如,在抽象类中:

this.HttpContext.RequestServices.GetService(typeof(YOUR_SERVICE));

控制器可以访问HttpContext。

第二种方法是在 Startup 中使用它,你可以这样做:

serviceCollection.AddScoped(typeof(ICmsDataContext), typeof(TDbContext));

其中serviceCollection是dotnet Core中的 IServiceCollection

希望它有所帮助。