Reputation: 8280
Recently I've found myself more and more getting into the habit of passing things by reference. I've always been taught that passing by ref is 'usually' a bad idea, as it's trickier to keep track of what could be affecting your objects, so I wanted to post the question: 'What are the cons of passing by reference?'
An example of where I've recently been passing by reference, is lazy-instantiated objects within the viewstate. Within my code-behind I have a private field, with a public property, that utilises a helper method. Current implement is as follows:
ASPX Code-behind
/// <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);
}
}
This aims to replace lots of repetitious if
assignment checks against fields and lazy-instantiated objects within a class. For example, without the helper class it would be something similar to.
/// <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;
}
}
Both snippets of code are achieving the same. The first approach is centralising everything, which is a good thing, however it is passing by reference, which in this instance I'm not sure is a good idea?
Any advice and / or experiences is greatly appreciated.
Edit
The GetValue
and SetValue
are extension methods on the ViewState. Code is supplied below.
/// <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;
}
Upvotes: 0
Views: 2437
Reputation: 24071
Could not resist to try out the Lazy<> class :-) thanks to 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;
Implementing a class for ViewState
would have following advantages:
To answer your original question: passing a reference allows other code to replace an object. We would have to trust the called function, that it doesn't pass this reference down to other objects, and replaces the original object anytime later.
Upvotes: 1
Reputation: 3828
Just some options to consider for this case.
You can achieve the same result with less lines of code and no ref:
get
{
if (this._myObject == null)
this._myObject = this.ViewState.GetValue<Foobar>("MyObject", new Foobar());
return this._myObject;
}
ViewState.GetValue returns object from ViewState if exists or sets and returns default (new FooBar()). I think this is quite canonical way to do lazy property initialization (or you can also use Lazy in .Net 4.0). You can even condense this to a single line:
return this._myObject = this._myObject ?? this.ViewState.GetValue("MyObject", new Foobar())
Also instead of passing by ref you can pass Action which sets private field like:
this.ViewState.GetValue("MyObject", new Foobar(), newValue => this._myObject = newValue);
I think this way ViewState and Foobar are less coupled.
And also instead of creating every time new Foorbar() for default value you can pass () => Foorbar() (or Lazy) so it will be created only once when it is needed.
So at least for your case I don't see any good reasons to use ref.
Upvotes: 1
Reputation: 1033
The forced pass by Reference is only interesting for primitive Objects like string or int.
If you do not use ref, you only pass the Value in the Function but pointing to an diffent Object in Memory.
Complex Objects like Classes are allways passed by reference if you use "ref" or not... That makes no difference at all ;-)
Upvotes: -1