通过引用传递的缺点是什么?

时间:2012-04-17 09:02:08

标签: c# .net

最近我发现自己越来越养成通过引用传递事物的习惯。我一直被告知,通过ref传递“通常”是一个坏主意,因为跟踪可能影响对象的东西比较棘手,所以我想发布一个问题:'传递的缺点是什么通过引用?'

我最近通过引用传递的示例是viewstate中的延迟实例化对象。在我的代码隐藏中,我有一个私有字段,带有一个公共属性,它使用了一个帮助方法。目前的工具如下:

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;
}

3 个答案:

答案 0 :(得分:1)

这个案例只考虑一些选项。

您可以使用更少的代码行来实现相同的结果,并且没有参考:

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

ViewState.GetValue从ViewState返回对象(如果存在)或设置并返回默认值(new 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()创建默认值时,您都可以传递()=&gt; Foorbar()(或Lazy)因此只在需要时才会创建一次。

所以至少在你的情况下我没有看到任何使用ref的理由。

答案 1 :(得分:1)

无法抗拒尝试Lazy&lt;&gt;上课:-)感谢戴夫。

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. 代码很快(没有类型转换)
  6. 回答原始问题:传递引用允许其他代码替换对象。我们必须信任被调用的函数,它不会将此引用传递给其他对象,并在以后随时替换原始对象。

答案 2 :(得分:0)

Reference的强制传递仅对字符串或int等原始对象很有用。

如果不使用ref,则只传递函数中的值,但指向内存中的不同对象。

如果使用“ref”或不使用“复杂对象”,那么像Classes一样通过引用传递... 这没有任何区别; - )