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

C# 通过引用传递的缺点是什么?,c#,.net,C#,.net,最近,我发现自己越来越养成了通过引用传递东西的习惯。我一直被教导,通过引用传递“通常”是一个坏主意,因为跟踪什么可能会影响你的对象更难,所以我想发布一个问题:“通过引用传递的缺点是什么?” 我最近通过引用传递的一个例子是viewstate中的惰性实例化对象。在我的代码隐藏中,我有一个私有字段,带有一个公共属性,它使用助手方法。目前的执行情况如下: ASPX代码隐藏 /// <summary> /// Private field member for MyObject /// <

最近,我发现自己越来越养成了通过引用传递东西的习惯。我一直被教导,通过引用传递“通常”是一个坏主意,因为跟踪什么可能会影响你的对象更难,所以我想发布一个问题:“通过引用传递的缺点是什么?”

我最近通过引用传递的一个例子是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);
    }
}
两段代码都实现了相同的功能。第一种方法是集中所有内容,这是一件好事,但是它是通过引用传递的,在这种情况下,我不确定这是一个好主意

非常感谢您的任何建议和/或经验

编辑
GetValue
SetValue
是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;
}
//
///如果类型正确且存在,则从当前视图状态获取值
/// 
公共静态T GetValue(此状态包源,字符串键,T@default)
{
//检查视图状态对象是否存在,并且类型是否正确
对象值=源[键];
如果(值==null | |!(值为T))
{
返回@default;
}
//从视图状态返回对象
返回(T)源[键];
}
/// 
///设置视图状态中的键值
/// 
公共静态void SetValue(此状态包源、字符串键、T值)
{
源[键]=值;
}
/// 
///如果类型正确且存在,则从引用字段辅助对象或当前视图状态获取值
/// 
///返回强类型会话对象或默认值
公共静态T GetValue(此状态包源,字符串键,T@default,ref T fieldHelper)
{
返回fieldHelper!=null?fieldHelper:fieldHelper=source.GetValue(key,@default);
}
/// 
///在视图状态和字段辅助对象中设置键值
/// 
///价值
公共静态void SetValue(此StateBag源、字符串键、T值、ref T fieldHelper)
{
源[键]=值;
fieldHelper=值;
}

强制按引用传递仅对字符串或int等基本对象感兴趣

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

如果您使用“ref”或不使用“ref”,像类这样的复杂对象总是通过引用传递。。。
这根本没什么区别;-)

>P>本案例中需要考虑的一些选项。 您可以使用更少的代码行和无引用来实现相同的结果:

get
{
    if (this._myObject == null)
        this._myObject = this.ViewState.GetValue<Foobar>("MyObject", new Foobar());
    return this._myObject;
}
此外,您可以传递设置私有字段的操作,而不是通过ref传递,如:

this.ViewState.GetValue("MyObject", new Foobar(), newValue => this._myObject = newValue);
我认为这样ViewState和Foobar就不那么耦合了

也不是每次都为默认值创建新的Foorbar(),而是可以传递()=>Foorbar()(或Lazy),这样在需要时只创建一次


因此,至少就你的情况而言,我看不出有什么好的理由使用ref。

忍不住尝试使用Lazy类:-),多亏了Dave

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;
公共类Foobar
{
}
公共类ViewState
{
private readonly Lazy_foobar=new Lazy();
公共饭馆懒散饭馆
{
获取{return\u foobar.Value;}
}
}
//获取或创建foobar
Foobar lazyFoobar=this.ViewState.lazyFoobar;
ViewState
实现类将具有以下优点:

  • 这是类型安全的
  • 延迟加载很容易集成
  • 不需要缓存对象(更稳定)
  • 代码是可读的
  • 代码很快(无类型转换)

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

    您在
    ViewState.GetValue(…)中没有检查和延迟实例吗目前?为什么在
    Foobar
    类中不能有一个泛型方法来为您执行此操作呢?我觉得这有点奇怪。为什么要将同一对象存储两次,一次在
    \u myObject
    中,一次在
    this.ViewState[“myObject”]
    ?第一个
    get
    完全没有返回,无论您是否使用它,您都会实例化一个新对象。可能的重复:可能的重复:如果您使用的是.NET 4,请检查将为您执行延迟初始化的延迟对象。另外,我假设Foobar是一个struct?
    复杂的对象,比如类,如果您使用“ref”或不使用“ref”,它们都是通过引用传递的。。。这根本没什么区别;-)…它确实会产生差异..如果您通过ref传递一个对象,您将能够更改引用(即,您可以使它引用其他对象)…但在另一种情况下,您只能更改对象成员的值..不清楚“基元类型”是什么意思。但是如果您指的是“值类型”,那么
    字符串
    就不是这样了。使用
    操作
    是对
    控件
    视图状态
    进行解耦的一个极好的答案。谢谢。:)此外,展望未来,我认为
    Action
    是一种比使用
    ref
    更合适的方法(对于我的示例),再次感谢。
    this.ViewState.GetValue("MyObject", new Foobar(), newValue => this._myObject = newValue);
    
    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;