0

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;
}
Richard
  • 8,110
  • 3
  • 36
  • 59
  • dont you have the checks and lazy-instansiation in the `ViewState.GetValue(...);` at the moment? Why can't you have a generic method in your `Foobar` class instead that does this for you? – default Apr 17 '12 at 09:24
  • 2
    This looks a bit strange to me. Why would you want to store the same object twice, once in `_myObject` and once in `this.ViewState["MyObject"]`? The first `get` has no return at all and you would always instantiate a new object, whether you use it or not. – martinstoeckli Apr 17 '12 at 09:24
  • possible duplicate: http://stackoverflow.com/questions/570471/whats-so-bad-about-ref-parameters – default Apr 17 '12 at 09:29
  • possible duplicate: http://stackoverflow.com/questions/804196/in-c-where-do-you-use-ref-in-front-of-a-parameter – default Apr 17 '12 at 09:29
  • 3
    If you're using .NET 4 check out the Lazy object which will do the lazy initialization for you. Also I'm assuming Foobar is a struct? – Dave S Apr 17 '12 at 09:31
  • @Dave S That looks interesting, thanks. – Richard Apr 17 '12 at 11:02
  • @martinstoeckli The reason for the multiple setting is for the prevention of ViewState calls, in attempts to micro-optimise null and type checking. There was also a typo in the first getter, which I've now edited. – Richard Apr 17 '12 at 11:02
  • Then i would recommend to make the ViewState a proper class with a property of type `Foobar`. The getter of this property can check for null and create an instance if necessary. That would make your application more stable (no cached objects/typesafe), easier to understand/maintain, and faster. – martinstoeckli Apr 17 '12 at 11:11
  • The ViewState is the control's ViewState. Adding a property to it would involve sub-classing the ViewState, adding that sub-classed to any 'base' controls, and then referencing that. It's a rather long winded approach to something that is much more generic, can be achieved with generics. – Richard Apr 17 '12 at 12:13
  • I see, then i would probably do something as Nikolay did in his first example. – martinstoeckli Apr 17 '12 at 12:24

3 Answers3

1

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.

Nikolay
  • 3,658
  • 1
  • 24
  • 25
  • Using `Action` is a fantastic answer to de-coupling the `Controls` and `ViewState`. Thank you. :) – Richard Apr 17 '12 at 12:25
  • Additionally, going forward, I think `Action` is a more appropriate method (for my examples) than using `ref`, so thanks again. – Richard Apr 17 '12 at 12:26
1

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:

  1. It's type safe
  2. Lazy loading is easy to integrate
  3. No cached objects are necessary (more stable)
  4. The code is readable
  5. The code is fast (no type conversion)

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.

martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
-1

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

sebastianmehler
  • 1,033
  • 1
  • 11
  • 23
  • 4
    `Complex Objects like Classes are allways passed by reference if you use "ref" or not... That makes no difference at all ;-)`...it does make differernce..if you pass by ref an object you will be able to change the reference(ie., you can make it refer to some other object)..but in the other case you can only change the values of the members of the object.. – techBeginner Apr 17 '12 at 10:24
  • 1
    It's unclear what you mean by “primitive type”. But if you mean “value type”, then `string` is not that. – svick Apr 17 '12 at 11:07