2013-03-25 110 views
0

我已經做了很多關於實例與靜態類的閱讀,還沒有找到我的問題的答案。在實例類引用的靜態類中實例化不同類時是否存在任何風險?實例類 - >靜態類 - > C#中的實例類

我正在使用的當前設計是在其中實例類調用靜態「記錄器」方法(傳遞一系列參數)以將錯誤記錄到文件系統中的文本文件中。我正在重構靜態「Logger」方法來實例化一個參數類(它只是一系列屬性和一些幫助方法,以XML或字符串的形式返回自身)以及一個DBLogger類,以便將錯誤記錄到數據庫而不是文件系統,傳遞參數類作爲唯一參數。

該模型在我的傳統VB6代碼中運行良好,其中Logger類是實例化的,不是靜態的。

但現在在.NET代碼中我不確定是否應該讓我的2個新類(參數和DBLogger)是靜態的,或者只是讓DBLogger靜態並實例化參數類。我擔心從靜態類創建(或不帶)實例的併發/多線程數據問題的可能性。我有權擔心還是無所謂?

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.IO; 

// all code truncated for illustration purposes 

namespace ThisIs.A.Test 
{ 
    //INSTANCE 
    public class ErrorLogParameters 
    { 
     private int mThreadId = 0; 
     private int mErrorNumber = 0; 
     private string mServerDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); 

     public int ThreadId 
     { 
      get { return mThreadId; } 
      set { mThreadId = value; } 
     } 
     public int ErrorNumber 
     { 
      get { return mErrorNumber; } 
      set { mErrorNumber = value; } 
     } 
     public string ServerDate 
     { 
      get { return mServerDate; } 
     } 
    } 

    //INSTANCE 
    public class ErrorLog 
    { 
     public void LogErrorToDatabase(ErrorLogParameters criteria) 
     { 
      //Log error to database here 
     } 
    } 

    //STATIC - Instantiates INSTANCE of ErrorLogParameters and ErrorLog 
    public class Logger 
    { 
     public static void WriteLog(string pstrObjectName, string pstrProcedureName, int plngErrNumber, string pstrErrDescription) 
     { 
      // create a new parameter object 
      ErrorLogParameters objParameters = new ErrorLogParameters(); 

      // populate object properties 
      objParameters.ErrorNumber = mlngErrNumber; 
      objParameters.ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; 

      ErrorLog objErrorLog = new ErrorLog(); 

      objErrorLog.LogErrorToDatabase(objParameters); 
     } 
    } 

    //INSTANCE - Invokes STATIC method 
    public class SomeInstance 
    { 
     private void ErrorHandler_Log(Exception exception, string procedureName, string additonalDescription, string stackTrace) 
     { 
      // call from instance class to static class 
      Logger.WriteLog(mstrObjectName, procedureName, mlngErrNumber, mstrErrDescription); 
     } 
    } 

} 
+0

你說的是單身模式嗎?記錄器通常以單身實現,所以我不認爲你會遇到很多問題。我認爲這個帶有子實例的記錄器的靜態概念很有意義。 – 2013-03-25 18:47:51

+0

如果您添加了代碼以更好地瞭解您正在談論的內容,那將非常有幫助。 – konkked 2013-03-25 19:19:01

回答

3

不,那是絕對沒問題 - 如果你要創建一個方法中的任何類的實例,也沒關係類聲明的方法是否是一個靜態類與否。

此外,除非你有一些「特殊」(例如靜態變量計算創建的實例的數量),你就不太可能創造新對象比時碰到併發問題使用現有對象時。基本上,幾乎所有併發的棘手部分是找出可變數據共享的地方 - 它不像那樣聲音(儘管示例代碼有助於澄清這一點)。

+0

我認爲你是我正在尋找的答案,但我現在已經添加了我的代碼示例。 – user2208719 2013-03-25 21:39:19

+0

@ user2208719:我會強烈地考慮改變你的'ErrorLogParameters'來保留'DateTime'(或'DateTimeOffset')作爲一個字段而不是一個字符串 - 讓調用者格式化它,如果他們想和他們想要的。我還會使用'UtcNow'而不是'Now' - 總是使用UTC來登錄,以便代碼運行在世界的哪個位置。 – 2013-03-25 21:43:55

0

我會爲此使用提供者和單例模式的組合。

創建一個名爲Logger的抽象類。

  1. Logger類包含寫入日誌的抽象方法。例如:
    • abstract void LogInfo(LogInfo info);
    • abstract void LogError(Exception exception);
  2. Logger類包含Logger對象的私有實例。
  3. Logger類包含一個返回私有實例的靜態屬性。
  4. Logger類包含一個靜態構造函數,用於實例化Logger對象的私有實例。您可能會使用Reflection並根據配置實例化對象。
  5. 實現繼承自Logger對象的FileLogger。該記錄器寫入文件。
  6. 實現從Logger對象繼承的SQLLogger。該記錄器寫入數據庫。

通話記錄器,像這樣:

  • Logger.Instance.WriteInfo(信息);
  • Logger.Instance.WriteError(exception);

有采用這種設計的一些優勢:

  1. 你的日誌記錄功能是完全抽象的。這將日誌記錄調用程序與寫入日誌的代碼完全分離。這使您可以將日誌寫入任何數據存儲。
  2. 您可以更改使用哪個記錄器而無需編譯代碼。只需更新配置文件。
  3. 單線程保證線程安全
  4. 可測試性。您可以針對抽象類編寫模擬測試。

希望這會有所幫助。

+0

謝謝,這是一個很好的選擇。 – user2208719 2013-03-25 21:10:49

0

靜態方法沒有併發問題。

靜態變量是另一回事。