Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shortest way to write immutable struct in C#

Quite often I come across the need for small immutable data structures. Others would probably use Tuples in these cases, but I really dislike that Tuples don't read nicely and don't express that much meaning. A Value2 of int doesn't tell me anything.

An example would be creating a lookup table (Dictionary) for a combination of two properties, i.e. Name and Rating.

The shortest way to make an immutable struct for these cases that I know of is this:

public struct Key
{
    public string   Name    { get; private set; }
    public int      Rating  { get; private set; }

    public LolCat(string name, int rating) : this()
    {
        Name    = name;
        Rating  = rating;
    }
}

// useage
var key = new Key( "MonorailCat", 5 );

In my opinion there is still a lot of 'syntactic fat' in here that I would like to get rid of. I could make it a lot more readable when I would just expose fields directly.

public struct Key
{
    public string   Name;
    public int      Rating;
}

// useage
var key = new Key { Name = "MonorailCat", Rating = 5 };

I really like the syntax of this, because there is barely any syntactic fat. The big disadvantage is of course that it is not immutable, with all it's dangers.

In the ideal case I would just like to have a special type for this, with the real bare minimum of definition, like:

public immutable struct Key
{
    string  Name;
    int     Rating;
}

// useage (needs compiler magic)
var key = new Key( Name: "MonorailCat", Rating: 5 );

Question

Is there a real world solution something closer to the example on the bottom, to reduce the amount of syntactic fat for a very simple immutable struct?

like image 644
Dirk Boer Avatar asked Sep 11 '14 12:09

Dirk Boer


1 Answers

As of C# 6, you can write fairly compact struct initializers:

public struct Key
{
    public string Name { get; }
    public int Rating { get; }

    public Key(string name, int rating)
    {
        this.Name = name;
        this.Rating = rating;
    }
}

... which is at least significantly shorter. I'd strongly advise implementing IEquatable<Key>, mind you.

Note that as you're dealing with a struct, you'll still be able to write:

Key key = new Key();
Console.WriteLine(key.Rating); // 0

... which may not be a problem, but generally needs considering at least.

Before C# 6, I'd actually go even longer than your current code, in order to write the properties as read-only properties:

public struct Key
{
    private readonly string name;
    private readonly int rating;

    public string Name { get { return name; } }
    public int Rating { get { return rating; } }

    public Key(string name, int rating)
    {
        this.name = name;
        this.rating = rating;
    }
}

I feel this makes it more clearly "meant to be immutable" - if you've got a writable property, even if the setter is only private, that doesn't convey the right impression IMO. (Although it's worth noting that immutability in structs is always a little bit of a pretense, given that you can assign to this in members...)

like image 169
Jon Skeet Avatar answered Oct 15 '22 03:10

Jon Skeet