2012-04-17 29 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. 代码是快速的(没有类型转换)

回答您的原始问题:传递引用允许其他代码替换对象。我们必须信任被调用的函数,它不会将此引用传递给其他对象,并在以后随时替换原始对象。