Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The CA2104 warning: Is there any way to mark a class as `Immutable` to suppress it?

Consider the following code, which provokes CA2104: Do not declare read only mutable reference types.

public class Test
{
    // This provokes CA2104: "Do not declare read only mutable reference types".
    protected readonly ImmutableClass ImmutableMember;
}

public class ImmutableClass
{
}

Does anyone know of a way to mark a class as immutable in a way that would suppress warning CA2104?

I tried decorating MutableClass with [ImmutableObject(true)] with no hope of success (since that attribute is pretty clearly for the Form Editor to use), and sure enough it doesn't work.

I assume that Code Analysis is using a list of known immutable types when determining whether to emit CA2104, so we can't use the same approach.

I guess that even if you could mark a class as immutable, there'd be no way for the compiler to actually check if it was true, but at least it could be a useful indicator.

Anyway, are there any attributes I'm overlooking? If not, suppression will have to do.

It seems that there is no alternative way to do this at the moment.

I did find an interesting blog from Joe Duffy (author of "Concurrent Programming On Windows") about this kind of thing.

He starts off with "Imagine we had an ImmutableAttribute."... :)

It's quite interesting - he went to the trouble of writing some new FxCop rules to do some analysis of types attributed as immutable.

like image 551
Matthew Watson Avatar asked Apr 01 '13 08:04

Matthew Watson


1 Answers

A protected readonly field isn't really that clear. As protected, you might expect that a derived class can initialize the field:

public class Test
{
    protected readonly ImmutableClass ImmutableMember;
}

public class SpecialTest : Test
{
    public SpecialTest() { ImmutableMember = new ImmutableClass; }
}

But, that's not the case--you will get a compile error (CS0191).

I don't know the exact impetus behind CA2104, but you can get the same result without readonly via:

public class Test
{
    protected ImmutableClass ImmutableMember {get; private set;}

    public Test()
        :this(new ImmutableClasse())
    {
    }

    public Test(ImmutableClass immutableClass)
    {
        ImmutableMember = new ImmutableClasse();
    }
}

and avoid the CA2104.

Update:

w.r.t. to the comments (and to future readers), as you say you could use a backing field to get the read-only and provide a protected getter to get at it in derived classes:

public class Test
{
    private readonly ImmutableClass immutableMember;

    protected ImmutableClass ImmutableMember { get { return immutableMember; } }

    public Test(ImmutableClass immutableMember)
    {
        this.immutableMember = immutableMember;
    }
}
like image 113
Peter Ritchie Avatar answered Oct 07 '22 02:10

Peter Ritchie