As you might know already, an object is immutable if its state doesn’t change once it has been created.

In C# the most used immutable type is string, this means every time you mod­ify the value of a string vari­able you are actu­ally cre­at­ing a new string object and updat­ing the ref­er­ence of the vari­able to point to the new object.

Class vs Struct

When cre­at­ing a new type, you have the choice of either a class or a struct. The gen­eral rule of thumb is to go with a class except for light­weight types smaller than 16 bytes in which case it is more effi­cient to use a struct. The rea­son a struct can be more effi­cient is because a struct is a value type and there­fore goes straight onto the stack so we don’t have the over­head of hav­ing to hold the ref­er­ence to the object itself (4 bytes in a 32bit system).

Muta­ble vs Immutable

In addi­tion, you also have to con­sider whether your type should be muta­ble or immutable. In gen­eral, a struct should always be immutable because a struct usu­ally rep­re­sents some fun­da­men­tal value – such as the num­ber 5 – and whilst you can change a variable’s value you don’t log­i­cally change the value itself.

Also, data loss is far too easy with muta­ble structs, con­sider the following:

Foo foo = new Foo(); // a mutable struct
foo.Bar = 27;
Foo foo2 = foo;
foo2.Bar = 55;

Now foo.Bar and foo2.Bar is dif­fer­ent, which is often unexpected.

Here are some of the advan­tages of using an immutable value type:

  • Eas­ier val­i­da­tion — if you val­i­date the para­me­ters used to con­struct your object, your object will never be invalid as its state can never be changed.
  • Thread safety — immutable types are inher­ently thread-safe because there is no chance for dif­fer­ent threads to see incon­sis­tent views of the same data if the data can never be changed.
  • Bet­ter encap­su­la­tion — immutable types can be exported from your objects safely because the caller can­not mod­ify the inter­nal state of your objects.
  • Bet­ter for hash-based col­lec­tions — the value returned by Object.GetHashCode() must be an instance invari­ant, which is always true for immutable types.

Dese­ri­al­iz­ing an Immutable Struct

To cre­ate an immutable struct, you usu­ally have no set­ters on prop­er­ties and in all like­li­hood the pri­vate vari­ables that the get­ters return will be made read­only too to enforce the write-once rule. The lack of pub­lic set­ters on prop­er­ties, how­ever, rep­re­sents a chal­lenge when serializing/deserializing the immutable structs.

The eas­i­est way to get around this in my expe­ri­ence is to sim­ply imple­ment the ISe­ri­al­iz­able inter­face and pro­vid­ing a con­struc­tor which takes a Seri­al­iza­tion­Info and a Stream­ing­Con­text object:

[Serializable]
public struct MyStruct: ISerializable
{
    private readonly int _x;
    private readonly int _y;

    // normal constructor
    public MyStruct(int x, int y) : this()
    {
        _x = x;
        _y = y;
    }

    // this constructor is used for deserialization
    public MyStruct(SerializationInfo info, StreamingContext text) : this()
    {
        _x = info.GetInt32("X");
        _y = info.GetInt32("Y");
    }

    public int X { get { return _x; } }
    public int Y { get { return _y; } }

    // this method is called during serialization
    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("X", X);
        info.AddValue("Z", Y);
    }
}

Ref­er­ence:

Stack­Over­flow thread on immutabil­ity of structs

Patrick Smacchia’s arti­cle on Immutable Types: under­stand their ben­e­fits and use them

Eric Lip­pert’s series on immutabil­ity in C#:

Immutabil­ity in C# Part One: Kinds of Immutability

Immutabil­ity in C# Part Two: A Sim­ple Immutable Stack

Immutabil­ity in C# Part Three: A Covari­ant Immutable Stack

Immutabil­ity in C# Part Four: An Immutable Queue

Immutabil­ity in C# Part Five: LOLZ!

Immutabil­ity in C# Part Six: A Sim­ple Binary Tree

Immutabil­ity in C# Part Seven: More on Binary Trees

Immutabil­ity in C# Part Eight: Even More On Binary Trees

Immutabil­ity in C# Part Nine: Aca­d­e­mic? Plus my AVL tree implementation

Immutabil­ity in C# Part Ten: A double-ended queue

Immutabil­ity in C# Part Eleven: A work­ing double-ended queue

Luca Bolog­nese’s series on imple­ment­ing immutable value objects:

Cre­at­ing an immutable value object in C# — Part I — Using a class

Cre­at­ing an immutable value object in C# — Part II — Mak­ing the class better

Cre­at­ing an immutable value object in C# — Part III — Using a struct

Cre­at­ing an immutable value object in C# — Part IV — A class with a spe­cial value

Cre­at­ing an immutable value object in C# — Part V — Using a library

Share

enum is a tremen­dously use­ful struc­ture in C#, but when defin­ing a new enum there is one thing you should always ask yourself:

What should the default value be for my enum?

The prob­lem with default value is that enum is really an int under­neath, and as do all inte­gers in C# an enum has a default value of 0 when first cre­ated. So if 0 is not mapped to an enu­mer­a­tion con­stant then your enum will be instan­ti­ated with an invalid valid:

public enum MyColour
{
    Red = 1,
    Green = 2,
    Blue = 3
}

MyColour colour = new MyColour(); // colour = 0, which is not a valid MyColour enumeration

Alter­na­tively, if you don’t spec­ify the inte­ger val­ues for the enu­mer­a­tions the enu­mer­a­tion by default will start at 0, and a new enum will be instan­ti­ated with the first value in the list. Again, there’s the prob­lem with the default value because most of the time there is no obvi­ous can­di­dates for the default value and it doesn’t make sense to just pick an arbi­trary enu­mer­a­tion to be the default value:

public enum MyColour
{
    Red,    // 0
    Green, // 1
    Blue    // 2
}

MyColour colour = new MyColour(); // colour = MyColour.Red, but should a new colour default to red??

This can lead to sub­tle bugs, and are often hard to pick up on. Take for exam­ple a class that uses the MyColour enum, if the pro­gram­mer who wrote the class for­get to set the value of the enum it’ll sim­ply read MyColour.Red, which is a valid case and with­out trac­ing through the code it’s dif­fi­cult to know whether the enum had been set to MyColour.Red purposefully.

There­fore it’s always bet­ter to mark the default value of an enum with some spe­cial enu­mer­a­tion such as None, or Unde­fined, etc.:

public enum MyColour
{
    Undefined = 0,
    Red = 1,
    Green = 2,
    Blue = 3
}
Share

If you’re read­ing this then you should already know what an enum is in C# and that the under­ly­ing type of an enum ele­ment is int and you can con­vert between int and enum using casting:

public enum MyColours { Red, Green, Blue}
...
MyColours red = MyColours.Red;
int redInt = (int) red; // this return 0, the default value for the first element in an enum
MyColours redFromInt = (MyColours) redInt; // this returns MyColours.Red

How­ever, some­times you want to con­vert an enum ele­ment to and from strings instead of ints because:

  1. they’re more humanly readable
  2. chang­ing the order of the ele­ments won’t break your application

If you have used an enum value as part of a string.Format call like this:

string.Format("Is your favourite colour [{0}]?", MyColours.Green);

Then you’ll see that the string lit­eral “Green” is dis­played rather than the under­ly­ing inte­ger, because the default ToString method has taken care of the enum to string con­ver­sion for you already. There is also an over­load of the ToString method which takes a for­mat string to allow you to return the inte­ger value, string name, or hexdec­i­mal rep­re­sen­ta­tion, see the exam­ples here.

To con­vert from a string name of a enum ele­ment back to its enum form you’ll need the help of the Enum class:

string redString = MyColours.Red.ToString(); // this returns "Red"
MyColours red = (MyColours)Enum.Parse(typeof(MyColours), redString); // this returns MyColours.Red

There are some other use­ful meth­ods on the Enum class such as IsDe­fined too, see the list of avail­able meth­ods here.

Share

Run­time type con­ver­sion is some­thing we all have to do from time to time, and in C#, type con­ver­sion is usu­ally done using either the as key­word or cast­ing.

Here’s a quick glance of how the two approaches differ:

Null ref­er­ence Con­ver­sion failure User-defined con­ver­sion Per­for­mance
as Null Null Ignored Fast
cast­ing Null Excep­tion Used Slow

Pre­fer as to casting

In Bill Wagner’s Effec­tive C# book, he rec­om­mends that you should use the as key­word when­ever pos­si­ble, because:

  • it’s more effi­cient at run­time, the as key­word (like the is key­word) does not per­form any user-defined con­ver­sion. It will only suc­ceed if the object is of the sought type (or derived from it) and never cre­ate a new object to sat­isfy a request.
  • requires less code because you don’t need a try-catch block in addi­tion to a null check.

There are a few things you should keep in mind when using the as keyword:

  • it doesn’t work with value types because value types can never be null
  • don’t use the is key­word if you’re using as for type con­ver­sion, it’s redun­dant because these two state­ments are equiv­a­lent except the as ver­sion eval­u­ates expres­sion only once!
expression as type
expression is type ? (type) expression : (type) null

When you should use casting

That’s not to say that you should never use cast­ing, a typ­i­cal use I have found work­ing with a Flash client is the need to con­vert busi­ness logic classes into AMFVO which are sim­ple con­tain­ers for a sub­set of the prop­er­ties of the logic classes and none of the behav­iour. In almost all cases like this I over­load the implicit/explicit oper­a­tor (see post on con­trol­ling type con­ver­sion here) and use cast­ing to invoke my cus­tom type con­ver­sions. The as key­word would not be appro­pri­ate in this case because the value object classes should never inherit from the busi­ness logic classes.

Gotcha!

Yup, there’s a gotcha with using cast­ing, and a pretty big one at that too!

The user-defined con­ver­sion oper­a­tors oper­ate only on the compile-time type of an object. What this means is that if no con­ver­sion oper­a­tor exists for the declared type of a vari­able the cast­ing oper­a­tion will fail even if a con­ver­sion oper­a­tor exists for the run­time type of that vari­able. I.E.

void Main()
{
    Player player = new Player { Name = "Me" };
    PlayerDTO playerDTO = (PlayerDTO) player; // this succeeds

    object player2 = new Player { Name = "You" };
    PlayerDTO playerDTO2 = (PlayerDTO) player2; // this fails, throws runtime InvalidCastException

    object player3 = new Player { Name = "They" };
    PlayerDTO playerDTO3 = player3 as PlayerDTO; // this fails, returns null

    Player player4 = new Player { Name = "It" };
    PlayerDTO playerDTO4 = player4 as PlayerDTO; // this won't compile

}

public class Player
{
    public string Name { get; set; }

    public static explicit operator PlayerDTO(Player player)
    {
        return new PlayerDTO(player.Name);
    }
}

public class PlayerDTO
{
    public PlayerDTO(string name)
    {
        Name = name;
    }

    public string Name { get; private set; }
}
Share

AMFVO is short for Action Message Format (AMF) Value Object (VO).

AMF is a binary for­mat used to seri­al­ize Action­Script objects, pri­mar­ily used to exchange data between a Flash appli­ca­tion and a remote ser­vice; a VO is also known as a Data Trans­fer Object (DTO), it is used to trans­fer data between appli­ca­tion subsystems.

An AMFVO is sim­ply a value object used to trans­fer Action­Script objects between a Flash appli­ca­tion and a remote service.

The most widely used AMF encod­ing frame­work for .Net is FlourineFX.

Share