2009-02-14 126 views
4

首先,static關鍵字。靜態關鍵字,狀態/實例變量和線程安全

我已閱讀過幾篇關於靜態關鍵字的文章和過去的主題。我還沒有找到許多我應該使用它的情景。我所知道的是,它不會在堆上創建一個對象,告訴我從性能的角度來看,對於很多對象來說這將是一件好事。

有沒有其他理由使用它?

此外,我已閱讀了關於static關鍵字的一些信息,以及它如何不應該與實例變量一起使用或更改狀態。有人可以澄清這一點嗎?看起來這是2 + 2的情況,但我無法得到答案(缺少一些基本和簡單的知識)。

最後,關於線程安全的話題,我應該在代碼中尋找什麼來獲得線程安全的想法?

我也在VB.NET中發佈了這個,因爲我不認爲不同的語言(C#/ VB.NET)會有不同的規則。

感謝

回答

4

static關鍵字在C語言中意味着不同,但在C#和Java中,它聲明的方法和變量是類而不是對象。

您可能希望將它用於不需要來自特定對象的任何數據的方法和變量,但對該類型的每個對象使用相同的數據。

例如String.Format()是String類的靜態方法。你在你的代碼中調用它而不創建一個String實例。同樣,Math.Pi將是一個類變量。

但類似長度的方法沒有任何意義,除非它作用在一個字符串的特定實例,所以它必須是一個實例方法。例如,x =「hello」.Length();

所以,如果你希望你的方法只有類名,而不是一個對象上調用,然後你做一個靜態方法。請注意,這樣的方法只能引用靜態變量並調用靜態方法,因爲它沒有引用非靜態成員的對象。

在C中,static關鍵字表示文件範圍聯動。頂級靜態變量或函數不會將其名稱導出到其他編譯目標代碼。所以兩個文件可以聲明同名的靜態變量而不會產生衝突。我們在C#中沒有這個問題,因爲有名稱空間,私有,保護和公共關鍵字來表示可見性。

另一個含義是在C函數內的靜態變量,這些變量保留調用函數之間的價值。例如,您可以使用一個來計算函數被調用的次數。 C#中的靜態變量也有這個屬性,但是你不要像在C中那樣在類中聲明它們。

-1

其實靜態變量不在堆棧上,他們保持在內存中的特殊部分是既不棧也不是堆。另外,無論堆或堆棧中的變量是否對性能都沒有影響。

靜態函數變量是存在於函數中的變量,如果更改,則會在調用之間保留它們的值。它們可以被認爲是按需初始化的全局值,只能用於聲明的函數中。國際海事組織真的沒有什麼好的理由在一個函數中使用靜態變量,除了偶爾進行一些測試。

靜態成員變量是一個類的所有實例之間共享的變量。所以如果你的「Person」有一個名爲「mCountry」的靜態成員,那麼所有的人都會共享這個變量。如果一個人改變它,每個人都會改變。靜態成員很有用,因爲它允許一個類的所有實例共享相同的數據,從而節省內存。

+0

其實我的意思是堆上的特殊部分(根據文章高頻堆)。猜猜我必須檢查這一點。另外,你說保留它們的價值,只用於它們聲明的函數 - 這聽起來像是一個範圍很小的常量/只讀值。 – dotnetdev 2009-02-14 01:34:41

+0

靜態變量是可變的,可以更改。所以,如果你有一個靜態的「計數」值的函數,你可以每次增加它 – 2009-02-14 01:37:21

+0

我發現了一些關於這個問題的好文章。實際上,作爲一個靜態字段,就像整個數據中的一個數據佔位符一樣,對於類似於應用程序版本的應用程序來說也是很好的。你不需要其中的一個以上。您可以將其設置爲靜態並更改它,但有1個實例。 – dotnetdev 2009-02-14 02:31:17

0

如果你想存儲每個實例唯一的東西,它應該是一個實例變量。如果您認爲每個實例不唯一(或不需要創建實例),則可以將其他數據設置爲靜態。

例如String.Empty(這是一個公共靜態只讀變量)。使用這個不需要你創建一個新的字符串實例。

0

我使用靜態變量來保存從文件中讀取的值(類似於sql查詢),這些值將在函數中被調用(比如在循環中)。每次調用函數時避免碰到磁盤,並且很好地利用了「信息隱藏」。

-1

這裏是一個很常見的用例的靜態類變量:

public class Foo 
{ 
    private static Dictionary<string, Foo> Foos = 
     new Dictionary<string, Foo>(); 

    public static Foo Create(string key) 
    { 
     if (Foos.ContainsKey(key)) return Foos[key]; 
     Foos.Add(key, new Foo(key)); 
    } 

    public string Key { get; set; } 

    private Foo(string key) 
    { 
     Key = key; 
    } 
} 

隱藏的構造函數和集合允許類本身促成所有富對象由應用程序創建。

1

最後,關於線程安全的話題,我應該怎麼找我的代碼來獲得一個想法線程安全?

編寫線程安全的代碼是一個沉重的話題,我不會進入這裏,但我會說靜態&線程安全的話題一兩件事。

大部分確保代碼的方法運行作爲用於多線程調用涉及某種鎖定的對象實例的。您會注意到,在.NET框架(BCL)中,所有靜態成員都是線程安全的。這是因爲沒有清楚的方式知道應該鎖定什麼樣的對象實例,以便在所有可能的呼叫者之間共享此資源。

舊準則來暗示鎖定的類型本身,即:

lock (typeof(SomeType)) 
{ 
    SomeType.SomeStaticMethod(...); 
} 

這種做法現在氣餒,是不可取的,因爲沒有在所有可以想象的控制訪問的這些鎖定對象的順序的方式調用線程。鎖定公共對象(包括ICollection.SyncRoot,因相同原因而被棄用)正在打開僵局的大門。在上面的例子中,類型實例是公共可用的,不應該被鎖定。

由於沒有一個統一的實例,它的靜態方法的所有客戶端可以在使用它們的靜態成員的訪問相當一致,微軟BCL團隊不得不做出所有靜態成員類型安全。值得慶幸的是,靜態成員很少。