2010-05-02 80 views
8

我願做這樣的事情:在靜態類中有狀態是不好的做法嗎?

public class Foo { 
    // Probably really a Guid, but I'm using a string here for simplicity's sake. 
    string Id { get; set; } 

    int Data { get; set; } 

    public Foo (int data) { 
     ... 
    } 

    ... 
} 

public static class FooManager { 
    Dictionary<string, Foo> foos = new Dictionary<string, Foo>(); 

    public static Foo Get (string id) { 
     return foos [id]; 
    } 

    public static Foo Add (int data) { 
     Foo foo = new Foo (data); 
     foos.Add (foo.Id, foo); 

     return foo; 
    } 

    public static bool Remove (string id) { 
     return foos.Remove (id); 
    } 

    ... 

    // Other members, perhaps events for when Foos are added or removed, etc. 
} 

這將讓我從任何地方管理的Foo論全球化集合。但是,我被告知靜態類應該永遠是無狀態的 - 你不應該使用它們來存儲全局數據。一般來說,全球數據似乎不受歡迎。如果我不應該使用靜態類,那麼解決這個問題的正確方法是什麼?

注意:我確實找到了similar question,但給出的答案並不適用於我的情況。

回答

9

誰留下那個靜態類應該是無狀態的?靜態意味着陳述。

只是知道類在CLR如何靜態工作:

  • 你無法控制的時候,靜態構造函數被調用。
  • 靜態類對於每個調用程序都有單獨的狀態。

還要注意併發性問題。

作爲一個便箋,令人驚訝的是,人們常說「不要使用X」。這就像有人走進你的工具箱並指向六種工具,並說:「這些工具是不好的做法。」這沒有意義。

+1

是的,我們都應該使用更多的全局變量和gotos ... – Lucas 2010-05-02 22:17:49

+1

當你必須使用它,但要聰明,以避免問題。稍後敏捷地轉向更好的東西。 – 2010-05-02 23:43:01

3

你似乎在這裏尋找的是單身類,而不是靜態類。靜態類和方法應該引用無狀態例程。一個singleton類每個應用程序只運行一次,並且具有類的全部功能。每次您在將來引用它時,都會返回具有完全相同成員屬性的完全相同的實例。

「C#singleton」的第一個谷歌結果似乎對實現有相當不錯的解釋。 http://www.yoda.arachsys.com/csharp/singleton.html

+1

請注意,雖然單例並不是很好的做法,因爲它們會創建依賴關係等等。最後,IoC(控制反轉)和依賴注入將是更好的解決方案。 – Femaref 2010-05-02 16:30:47

4

全局數據既強大又常見的問題來源,這就是爲什麼使用依賴注入等技術的原因。你可以把它看作是一個正常的解耦問題。讓您的程序中很多地方直接引用全局數據,可以在全球數據和所有這些地方之間建立強大的聯繫。

但在您的示例中,您已將數據訪問權隔離到一個類中,該類控制全局數據訪問的確切詳細信息。由於一些全球數據通常是不可避免的,我認爲這是一個好方法。

你可以比較一下如何通過.NET框架使用app.config和web.config。他們通過靜態類System.Configuration.ConfigurationManager訪問,靜態屬性AppSettings,它隱藏瞭如何到達全局數據的細節。

2

這並不普遍不好。在一些罕見的情況下,需要這樣做,而不是執行其他有大量開銷的東西。

但建議注意threadsafety。

您應該鎖定對字典的每個調用,以便一次只有一個線程可以訪問它。


private static readonly object LockStaticFields = new object(); 

public static Foo Add (int data) { 
     lock(LockStaticFields) 
     { 
      Foo foo = new Foo (data); 
      foos.Add (foo.Id, foo); 

      return foo; 
     } 
    } 

+0

我想補充一句:如果你在多線程環境下工作,你應該鎖定每一個字典的調用。否則它將無用的開銷 – Budda 2010-07-24 03:41:32

+0

嗯,也許你是對的。但是我的經驗告訴我,總是這樣做更好。我在公司工作,現在不得不重構幾乎所有的東西,因爲最初它並沒有在多線程環境中實現。我認爲這比第一次實施線程安全成本要高得多,儘管您可能不需要這種安全性。 – DHN 2010-07-24 06:54:49

0

在你的類中使用只讀靜態屬性,這個屬性在類的所有實例中都是相同的。按照需要從構造函數中遞增和遞減等。

0

我在靜態類中始終使用永遠不會(或極少)變化的事情的列表 - 這對於加載選擇列表以及不需要每次都敲擊db都很方便。由於我不允許更改,因此我不必擔心鎖定/訪問控制。

0

要考慮的另一件事是應用程序本身和它的預算。真的需要比靜態類更復雜的東西嗎?

相關問題