2009-08-18 30 views
21

Tôi có một lớp tĩnh trong đó kêu gọi một lớp Logger tĩnh,Dependency Injection với một logger tĩnh, tĩnh helper class

ví dụ

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

Làm thế nào để tôi tiêm Logger vào lớp tĩnh của tôi?

Lưu ý: Tôi đã đọc Dependency Injection in .NET with examples?, nhưng điều này dường như sử dụng trình ghi nhật ký.

Trả lời

24

Bạn không thể tiêm một trình ghi nhật ký tĩnh. Bạn phải thay đổi nó thành một trình ghi log (nếu bạn có thể), hoặc bọc nó trong một trình ghi ký tự thể hiện (mà sẽ gọi là tĩnh). Ngoài ra nó là khá khó để tiêm bất cứ điều gì đến một lớp tĩnh (bởi vì bạn không kiểm soát các constructor tĩnh trong bất kỳ cách nào) - đó là lý do tại sao tôi có xu hướng vượt qua tất cả các đối tượng tôi muốn tiêm như các tham số.

21

Điều này không nhất thiết phải như vậy. Chừng nào logger tĩnh của bạn cho thấy một phương pháp để:

  • Injection của các lớp bạn muốn tiêm, hoặc
  • Injection của DI container trong một cuộc gọi phương pháp thích hợp trước khi chạy nó (nói trong một cái gì đó giống như asp .net global.asax Application_Start method), sau đó bạn sẽ ổn thôi.

Đây là một ví dụ. Lấy lớp sau cho DI:

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

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

Và đây là lớp tĩnh của chúng tôi mà cần một logger:

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


    } 

Bây giờ, trong một khởi động toàn cầu cho ứng dụng của bạn (trong trường hợp này, trong global.asax của tôi .cs), bạn có thể khởi tạo DI Container của bạn, sau đó đưa nó cho lớp tĩnh của bạn.

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"); 

     } 

Và mau! Bạn hiện đang hoạt động với DI trong các lớp tĩnh của bạn.

Hy vọng rằng sẽ giúp ai đó. Tôi đang làm việc lại một ứng dụng sử dụng rất nhiều các lớp tĩnh, và chúng tôi đã sử dụng nó thành công trong một thời gian.

+5

Dường như tôi giống như độ phân giải phụ thuộc hơn so với tiêm phụ thuộc. Lớp tĩnh bây giờ có kiến ​​thức về khung phụ thuộc. Nhưng sẽ không khó để thích ứng với nó để tránh nó. (Giải quyết trong application_start và khởi tạo với phụ thuộc giải quyết, thay vì cung cấp giải quyết trong khởi tạo.) –

+0

Câu hỏi đặt ra là tiêm một lớp tĩnh vào một lớp tĩnh. Điều này đề cập đến cách tiêm một cá thể không tĩnh vào một lớp tĩnh. Điều này giống như một câu trả lời cho câu sau trong câu trả lời trước: "Ngoài ra nó là khá khó để tiêm bất cứ điều gì đến một lớp tĩnh" –

+0

Điều này có vẻ quá phức tạp cho một cái gì đó đơn giản như một logger. – rolls

0

Tôi không chắc Logger hoạt động như thế nào, nhưng thông thường bạn có thể sử dụng RequestService để lấy ví dụ của mình. Ví dụ: trong lớp trừu tượng:

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

Có thể điều khiển, nơi bạn có thể truy cập vào HttpContext.

Cách thứ hai là sử dụng nó ví dụ như trong Startup, nơi bạn có thể làm điều này:

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

nơi serviceCollection là IServiceCollection trong DotNet Core.

Hy vọng điều đó sẽ hữu ích.

1

Đây là cách rất đơn giản để "tiêm" chức năng của trình ghi nhật ký tĩnh.

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 
    } 
} 
Các vấn đề liên quan