A little syntactic sugar to have reference semantics for value types

In C#, structs and other data primitives have value semantics. (This includes strings, even though they are technically reference types.) But sometimes it’s useful to have reference semantics when dealing with what would otherwise be a value type. (Referencing primitives in a singleton object, for example.)

Here are two ways of doing that.

Delegates

Delegate syntax can seem a little weird–particularly when you’re working with primitives–because they’re basically typed function pointers. They look more like methods than variables.

Here’s an example:

class Program
{
    static void Main(string[] args)
    {
        var i = SomeInteger.SomeNumber;     //Value type won't change when SomeNumber changes
        Console.WriteLine(i);               //100
        Func<int> del = () => SomeInteger.SomeNumber;
        Console.WriteLine(del());           //100 (Same as del.Invoke())
 
        SomeInteger.SomeNumber = 42;
        Console.WriteLine(i);               //Still 100
        Console.WriteLine(del());           //42
    }
}
 
static class SomeInteger
{
    public static int SomeNumber = 100;
}

Wrapper class using generics

My preferred way is by combining a wrapper class with C# generics. It has nicer syntax, but does require a little more setup. The results are a little clearer, in my opinion.

Here’s an example:

class Program
{
    static void Main(string[] args)
    {
        //Assume SomeInteger.SomeNumber is 100 again
        var foo = new Reference<int>(() => SomeInteger.SomeNumber);
        Console.WriteLine("foo.Value: {0}", foo.Value);     //100
 
        SomeInteger.SomeNumber = 42;
        Console.WriteLine("foo.Value: {0}", foo.Value);     //42
    }
}
 
class Reference<T>
{
    private readonly Func<T> _theValue;
    public T Value
    {
        get
        {
            //If the value is null, return the default initialization of type T
            return _theValue != null ? _theValue.Invoke() : default(T);
        }
    }
 
    public Reference(Func<T> theValue)
    {
        _theValue = theValue;
    }
}

And there we have type-safe, reference semantics for primitives in C#. (Works for nullable types, too.)

Leave a Reply

Your email address will not be published.