最近我发现自己越来越养成通过引用传递事物的习惯。我一直被告知,通过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;
}
}
两段代码都达到了相同的效果。第一种方法是集中所有东西,这是一件好事,但它是通过引用传递的,在这种情况下我不确定是一个好主意?
非常感谢任何建议和/或经历。
修改
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;
}
答案 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
实现一个类具有以下优点:
回答原始问题:传递引用允许其他代码替换对象。我们必须信任被调用的函数,它不会将此引用传递给其他对象,并在以后随时替换原始对象。
答案 2 :(得分:0)
Reference的强制传递仅对字符串或int等原始对象很有用。
如果不使用ref,则只传递函数中的值,但指向内存中的不同对象。
如果使用“ref”或不使用“复杂对象”,那么像Classes一样通过引用传递... 这没有任何区别; - )