5

I currently know of two ways to make an instance immutable in C#:

Method 1 - Compile Time Immutability

void Foo() 
{
    // Will be serialized as metadata and inserted
    // as a literal. Only valid for compile-time constants
    const int bar = 100;
}

Method 2 - Readonly Fields

class Baz
{
    private readonly string frob;

    public Baz()
    {    
         // Can be set once in the constructor
         // Only valid on members, not local variables
         frob = "frob";
    }
}

It would be nice to have a guarantee that, some instance, once instantiated, will not be changed. const and readonly do this to a small degree, but are limited in their scope. I can only use const for compile-time constants, and readonly for member variables.

Is there any way to give a local variable immutability after its initial instantiation (the way readonly works, but on a more general level)?


Scala does this with the var keyword, which declares a new immutable value, which cannot be reassigned to after it gets its initial value:

var xs = List(1,2,3,4,5) // xs is a value - cannot be reassigned to
xs = List(1,2,3,4,5,6);  // will not compile
KChaloux
  • 3,918
  • 6
  • 37
  • 52
  • If you are using read-only fields, they should still be private and exposed via a `get` only property. – Trevor Pilley Jul 26 '13 at 14:11
  • @Trevor I'll edit the question for the sake of not having that come up again :p It's not the focus of the question (nor is this actually code that's being used in production, of course. It's more an academic question) – KChaloux Jul 26 '13 at 14:13
  • Some ideas here: http://stackoverflow.com/questions/1120999/make-object-immutable-at-runtime-c ... one idea I have is perhaps you could use AOP to weave in some code to "protect" set access to properties, etc....you'd need to look into using an AOP framework and writing the code – Colin Smith Jul 26 '13 at 14:14
  • Scala uses the immutablitiy to improve performance and enable easier parallelism, C# has no such benefits. Also Scala uses val for immutable and var for variables (can be changed). To do this in C# you would have to make a wrapper class that determines whether the value can be read. – MrFox Jul 26 '13 at 14:14
  • @MrFox I thought about wrappers, but what's to prevent the wrapper from being assigned to? I'm actually coming at this from a maintenance perspective, having worked with a huge codebase full of values, many of which are never changed after assignment, and I'd love to be able to ignore, but there's no way to tell that they haven't been changed without looking for all references to them. – KChaloux Jul 26 '13 at 14:19
  • 1
    Also see this: http://stackoverflow.com/questions/263585/immutable-object-pattern-in-c-sharp-what-do-you-think – Colin Smith Jul 26 '13 at 14:20
  • @colinsmith I'll look into it. It appears that there's no language-level way to do what I want, but the link looks interesting. – KChaloux Jul 26 '13 at 14:22
  • And this for the detailed article on in from a Microsoftie: http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx – Colin Smith Jul 26 '13 at 14:25

2 Answers2

5

You can't prevent variables from being re-assigned in C# with the exception of fields, by as you have already mentioned using const or readonly.

You could make your own immutable version of any existing mutable type by wrapping it or if it's your own class, re-write it to be immutable but you can't achieve it for variables in a method which is what your question seems to be getting at.

F# has a few options for immutability (the 'let keyword if I'm remembering correctly) that C# doesn't so it might be worth looking at F# if you still want to leverage the power of .NET but with complete immutability.

Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
  • Yes, I've dabbled in F# a bit, and it handles immutability the way I'd like it to. Alas, my day-job is in C#, and I'm fairly positive I won't be getting any sort of adoption to switch languages :p (We just barely got the other guys off of VB). This appears to be the answer. I'll accept it when I can. – KChaloux Jul 26 '13 at 14:21
  • Don't forget: Readonly is easily overriden with reflection. The only way to archive immutability is using a `struct` as it will always be a copy when used! – Felix K. Jul 26 '13 at 15:15
  • @FelixK. only when it's passed as a parameter to another method, you could still do the reflection hack to change a struct property and read its 'new' value inside the same method. – Trevor Pilley Jul 26 '13 at 15:22
  • @TrevorPilley Right when you are able to override the existing property, field or whatever you are able to. – Felix K. Jul 27 '13 at 08:33
1

If the wrapper is static it cannot be overwritten. This does sacrafice compile time checking on variable names and type safety.

public static class ReadOnly
{
    private static readonly Dictionary<string, object> values = new Dictionary<string, object>();

    public static bool SetValue(string name, object data)
    {
        if (values.ContainsKey(name))
            return false;

        values[name] = data;

        return true;
    }

    public static object GetValue(string name)
    {
        return values[name];
    }
}


        ReadOnly.SetValue("xs", 1);
        ReadOnly.SetValue("xs", 1); // will crash
MrFox
  • 4,852
  • 7
  • 45
  • 81