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

36

我有一个静态类,调用一个静态的Logger类,例如:

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?,但该示例似乎使用实例化的Logger。

4个回答

43

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

  • 注入您想要注入的类,或
  • 在适当的方法调用中注入DI容器(例如在像ASP.NET全局.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");

        }

瞧!你现在已经在静态类中安装并运行了DI。

希望这能对某个人有所帮助。我正在重新设计一个使用了很多静态类的应用程序,我们一直在成功地使用这种方法。


10
在我看来,这更像是依赖关系解析而不是依赖注入。现在静态类已经了解了依赖关系框架。但很容易进行适应以避免此情况。(在application_start中解析,然后使用已解析的依赖项进行初始化,而不是在初始化时提供解析器。) - Frédéric
问题是关于将一个静态类注入到另一个静态类中。这涉及如何将非静态实例注入到静态类中。 这似乎是对先前答案中以下声明的回应:“同时,向静态类注入任何内容都相当困难”。 - Andy Thomas
这个似乎对于一个简单的记录器而言过于复杂了。 - rollsch
这是模拟静态类的唯一方法。 - sensei

38

你不能注入一个静态日志记录器。你必须要将它改成实例日志记录器(如果可以的话),或者将其包装在一个实例日志记录器中(这将调用静态日志记录器)。另外,向静态类注入任何东西都相当困难(因为你无法以任何方式控制静态构造函数) - 这就是为什么我倾向于将我想要注入的所有对象作为参数传递的原因。


说句题外话,我只想说你可以使用静态构造函数,但是你无法传递任何构造函数参数,因为这是严格禁止的。 - dyslexicanaboko

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
    }
}

0

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

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

在控制器中,您可以访问HttpContext。

第二种方法是在启动中使用它,您可以这样做:

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

在dotnet Core中,serviceCollection是IServiceCollection

希望对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接