2012-04-17 61 views
0

最近我發現自己越來越習慣於通過引用傳遞事物。我總是被教導說,通過ref通常是一個糟糕的主意,因爲跟蹤可能會影響你的對象的事情是比較棘手的,所以我想提出這個問題:'通過引用傳遞的缺點是什麼?通過引用傳遞的缺點是什麼?

我最近通過引用傳遞的示例是視圖狀態中的延遲實例化對象。在我的代碼後面,我有一個私有領域,有一個公共財產,它使用了一個輔助方法。當前實現如下:

ASPX代碼隱藏

/// <summary> 
/// Private field member for MyObject 
/// </summary> 
private Foobar _myObject = null; 

/// <summary> 
/// Gets or sets the current object 
/// </summary> 
public Foobar MyObject 
{ 
    get 
    { 
     return this.ViewState.GetValue("MyObject", new Foobar(), ref this._myObject); 
    } 
    set 
    { 
     this.ViewState.SetValue("MyObject", value, ref this._myObject); 
    } 
} 

這旨在取代大量針對一類中的字段和懶惰的實例化對象重複if分配檢查。例如,沒有助手類,它會是類似的東西。

/// <summary> 
/// Private field member for MyObject 
/// </summary> 
private Foobar _myObject = null; 

/// <summary> 
/// Gets or sets the current object 
/// </summary> 
public Foobar MyObject 
{ 
    get 
    { 
     if (this._myObject != null) 
     { 
      return this._myObject; 
     } 

     var viewStateValue = this.ViewState["MyObject"]; 
     if (viewStateValue == null || !(viewStateValue is Foobar)) 
     { 
      this.ViewState["MyObject"] = new Foobar(); 
     } 

     return this._myObject = (Foobar)this.ViewState["MyObject"]; 
    } 
    set 
    { 
     this._myObject = value; 
     this.ViewState["MyObject"] = value; 
    } 
} 

這兩個代碼片段都達到了相同。第一種方法是集中所有東西,這是件好事,但它是通過引用傳遞的,在這種情況下,我不確定是個好主意嗎?

任何意見和/或經驗,不勝感激。

編輯GetValueSetValue都在ViewState的擴展方法。代碼在下面提供。

/// <summary> 
/// Gets a value from the current view state, if the type is correct and present 
/// </summary> 
public static T GetValue<T>(this StateBag source, string key, T @default) 
{ 
    // check if the view state object exists, and is of the correct type 
    object value = source[key]; 
    if (value == null || !(value is T)) 
    { 
     return @default; 
    } 

    // return the object from the view state 
    return (T)source[key]; 
} 

/// <summary> 
/// Sets the key value within the view state 
/// </summary> 
public static void SetValue<T>(this StateBag source, string key, T value) 
{ 
    source[key] = value; 
} 

/// <summary> 
/// Gets a value from the reference field helper, or the current view state, if the type is correct and present 
/// </summary> 
/// <returns>Returns a strongly typed session object, or default value</returns> 
public static T GetValue<T>(this StateBag source, string key, T @default, ref T fieldHelper) 
{ 
    return fieldHelper != null ? fieldHelper : fieldHelper = source.GetValue(key, @default); 
} 

/// <summary> 
/// Sets the key value within the view state and the field helper 
/// </summary> 
/// <param name="value">The value</param> 
public static void SetValue<T>(this StateBag source, string key, T value, ref T fieldHelper) 
{ 
    source[key] = value; 
    fieldHelper = value; 
} 
+0

你沒有'ViewState.GetValue(...);'此刻的檢查和lazy-instansiation?爲什麼你不能在你的Foobar類中使用泛型方法,而是爲你做這個工作? – Default 2012-04-17 09:24:29

+2

這對我來說看起來有點奇怪。爲什麼要將相同的對象存儲兩次,一次存儲在__ __ ___中,一次存儲在'this.ViewState [「MyObject」]中?第一個'get'根本沒有任何回報,你總是會實例化一個新的對象,不管你是否使用它。 – martinstoeckli 2012-04-17 09:24:54

+0

可能的重複:http://stackoverflow.com/questions/570471/whats-so-bad-about-ref-parameters – Default 2012-04-17 09:29:13

回答

1

只是一些選項沒有區別考慮這種情況。

可以用較少的代碼行,並沒有REF獲得相同的結果:

get 
{ 
    if (this._myObject == null) 
     this._myObject = this.ViewState.GetValue<Foobar>("MyObject", new Foobar()); 
    return this._myObject; 
} 

ViewState.GetValue返回從ViewState對象中是否存在或集並返回缺省值(新FooBar的())。我認爲這是執行懶惰屬性初始化的非常典型的方法(或者您也可以在.Net 4.0中使用Lazy)。此外

return this._myObject = this._myObject ?? this.ViewState.GetValue("MyObject", new Foobar()) 

,而不是由裁判通過,你可以通過這臺私人領域一樣行動:你甚至可以凝聚這一條線

this.ViewState.GetValue("MyObject", new Foobar(), newValue => this._myObject = newValue); 

我覺得這樣的ViewState和Foobar的不太再加。 ()=> Foorbar()(或Lazy),所以它只會在需要時創建一次,而不是每次創建新的Foorbar()爲默認值。

所以至少對於你的情況,我沒有看到任何好的理由使用ref。

+0

使用'動作'是將'Controls'和'ViewState'分開的絕佳選擇。謝謝。 :) – Richard 2012-04-17 12:25:27

+0

此外,向前看,我認爲'動作'是比使用'ref'更合適的方法(對於我的示例),所以再次感謝。 – Richard 2012-04-17 12:26:20

0

通過引用強制傳遞只對基本對象如string或int感興趣。

如果不使用ref,則只傳遞函數中的值,但指向內存中不同的對象。

像類複雜對象的八方通通過引用傳遞的,如果你用「裁判」或不... 這使得在所有;-)

+3

'像Classes這樣的複雜對象如果使用「ref」或者不用,那麼這些複雜對象就像通過引用一樣被傳遞......這根本就沒有任何區別;-)'......它確實有差異..如果你通過ref來傳遞一個對象,能夠更改引用(即,可以使其引用其他對象)..但在另一種情況下,您只能更改對象成員的值。 – dotNETbeginner 2012-04-17 10:24:23

+0

您不清楚「原語類型」。但如果你的意思是「值類型」,那麼'string'就不是那個。 – svick 2012-04-17 11:07:55

1

感謝戴夫,忍不住去嘗試懶惰的<> class :-)。

public class Foobar 
{ 
} 

public class ViewState 
{ 
    private readonly Lazy<Foobar> _foobar = new Lazy<Foobar>(); 

    public Foobar LazyFoobar 
    { 
    get { return _foobar.Value; } 
    } 
} 

// Gets or creates the foobar 
Foobar lazyFoobar = this.ViewState.LazyFoobar; 

實現一類ViewState將有以下優點:

  1. 它的類型安全
  2. 延遲加載易於集成
  3. 沒有緩存的對象是必要的(更穩定)
  4. 該代碼是可讀的
  5. 代碼是快速的(沒有類型轉換)

回答您的原始問題:傳遞引用允許其他代碼替換對象。我們必須信任被調用的函數,它不會將此引用傳遞給其他對象,並在以後隨時替換原始對象。