2012-01-11 73 views
-3

我已閱讀過靜態與實例方法,但我沒有看到任何回答這個特定問題(綠色,因爲它可能)。靜態與實例方法需要值時的最佳實踐

如果您有一個具有某些屬性的類,並且該類中需要使用這些屬性的方法,那麼使用靜態方法還是實例方法更好?

I.E.

class Foo 
{ 
    //properties 
    bar1; 
    bar2; 

    //method 
    sumbar1andbar2() 
    { 
     return bar1 + bar2; 
    } 
} 

sumbar1andbar2方法需要存在Foo類的屬性。這似乎有點愚蠢,使靜態方法和這樣調用它,因爲我手動傳遞的類的成員到類的方法:

Foo foo1 = new Foo(); 
foo1.bar1 = x; 
foo1.bar2 = y; 
sumbar1andbar2(foo1.bar1, foo1.bar2); 

不過,雖然下面的實例方法看起來乾淨多了,我「M不知道乾淨和簡單的方法,以確保兩個BAR1和BAR2不爲空,這將導致一個例外:

Foo foo1 = new Foo(); 
foo1.bar1 = x; 
foo1.bar2 = y; 
sumbar1andbar2(); 

但是,實例方法似乎更好,如果方法修改的另一個屬性類,像bar3。

+3

實際編譯的郵政編碼,所以我們可以有一個可能的答案拍攝。 – 2012-01-11 23:44:51

回答

1

首先,是要確保你的屬性非空一個很好的和簡單的方法:它被稱爲封裝。確保屬性在構造函數中設置,並且如果選擇公開一個,則在其setter中進行驗證。這樣,在構造對象之後屬性將是非空的(否則,構造函數會拋出異常),並且屬性設置器會將屬性值保留爲一致的狀態(否則,設置器將拋出異常)。

現在回到實際問題:如果其中一個或兩個值可能爲潛在來自Foo的其他實例,則使計算方法爲靜態。否則,使其成爲實例方法。

P.S.如果你的方法返回一個值,沒有參數,並且不產生副作用,考慮使它成爲一個計算的屬性而不是方法。

+0

謝謝dasblinkenlight!這就是我一直在尋找的。封裝是我一直在尋找的。由於自學成功,我錯過了大多數人在101課程中可能學到的一些東西。 – 2012-01-12 00:13:32

2

如果該方法的行爲對於類型Foo是唯一的(並且在其他地方不適用),或者它修改了Foo的狀態,那麼您應該將其作爲Foo的實例方法。

如果是,你可能要在其他地方使用它的通用計算(如你的例子),你有幾種選擇:

使它成爲一個實用工具類,例如靜態方法

public static class MyUtility { 
    public static Int32 Add(Int32 x, Int32 y) { return x + y; } 
} 

使它上富一個extension method,它的父類,或定義x和y的接口,例如

// Use as follows: 
// var f = new Foo() { x = 5, y = 5 }; 
// var ten = f.MyUtility(); 
public static class MyUtility { 
    public static Int32 Add(this Foo foo) { return Foo.x + Foo.y; } 
} 
+0

沒有理由爲你所擁有的課程制定擴展方法。 – 2012-01-11 23:53:29

+0

我同意。我沒有說他應該。 – 2012-01-11 23:57:38

+0

謝謝克里斯!這有幫助。 – 2012-01-12 17:46:18

2

如果它涉及特定實例,那麼它必須是實例成員(無論是方法,屬性還是字段)。這些是最常見的情況,所以例子很多。

如果它與特定實例無關,那麼實例成員需要一個不會以任何其他方式使用的實例。一個很好的例子是Math.Max,如果您致電Math.Max(43, 23),那麼結果與43大於23的事實有關,而不涉及Math對象的任何可能在應用程序運行過程中發生更改的屬性。

有些類只需要靜態成員,所以我們讓類本身是靜態的,它根本不能被實例化。

由於相同的原因,涉及類的性質而非給定實例的Propeties也應該是靜態的。例如。 int.MaxValueint的財產,而不是例如。 93.

請注意,int.MaxValue的結果本身就是int。這並不罕見。其他例子包括TimeSpan.Zerostring.Empty。這可以是一種方便,有時也可以在防止大量重複引用類型方面帶來性能優勢(在值類型的情況下不相關,在引用類型的情況下不會過分陳述)。重要的是不要這樣做。我們不想在int上使用4294967296不同的靜態屬性來使它們「很容易」稱呼它們!通常這在以下情況下有用:

特殊情況不能由構造函數構造。

OR:

的特殊情況是常用(TimeSpan.Zero)和/或不方便記憶(int.MaxValue更清晰,更容易比2147483647甚至0x7FFFFFFF召回)。更重要的是,如果兩者都是。

擴展方法是可以像調用實例成員一樣調用的靜態方法。它們非常方便,但通常情況下最好使用實例成員。他們是有用的,當一個實例成員是不可能的,因爲:

  1. 您沒有訪問類的源(這是另一個黨的階級)。
  2. 你想在接口而不是類上定義它。
  3. 您希望它可以在null上調用(避免,這在C#中是非慣用的,但在其他語言中更常見)。
  4. 你想爲泛型的特定情況定義它。例如,如果我創建了實現IDictionary<TKey, TValue>MyDictionary<TKey, TValue>,我無法定義plus方法,該方法向存儲的值添加一個數字,因爲只有當TValue是已知的數字類型時纔可以使用該方法。我可以將這種方法定義爲一種擴展方法,如int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend),當TValue爲int時,它將會像實例成員一樣出現,但不會干擾其他類型參數使用MyDictionary

所有這些情況都讓您別無選擇,只能使用擴展方法,但在實例成員執行此作業時不要使用它們。它更清晰,尤其是因爲其他一些.NET語言只會將擴展成員視爲靜態。

+0

偉大的信息,謝謝喬恩! – 2012-01-12 17:52:40