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