63

I found a topic on MSDN that talks that yes, this is possible.

I did a test that seems to break this statement:

using System;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo f = new Foo("1");
            Console.WriteLine(f.Bar); // prints 1
            f.Test("2");
            Console.WriteLine(f.Bar);// successfully prints 2
        }
    }

    class Foo
    {
        public Foo(string b)
        {
            this.Bar = b;
        }

        public string Bar { get; private set; }

        public void Test(string b)
        {
            // this would be impossible for readonly field!
            // next error would be occur: CS0191 or CS0191
            // A readonly field cannot be assigned to (except in a constructor or a variable initializer)
            this.Bar = b; 
        }
    }
}

Where am I wrong?

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • 4
    I think you are testing for the wrong kind of read-only here. Your code just says that you are not allowed to set the property Bar directly from anywhere outside the class nor from subclasses (private setter). Your class methods can still change the variable if the setter is private. –  Mar 19 '10 at 20:55
  • 1
    ummm... what about `public readonly string Bar;`? – peterchen Mar 19 '10 at 21:05
  • @dbemerlin: I'm talking about readonly in sense of the keyword. Not about levels of access. There is an appropriate topic on MSDN: http://msdn.microsoft.com/en-us/library/ba0a1yw2.aspx. I think there is only one kind of read-only in C#. Everything else is just everything else, not read-only in C# :) – abatishchev Mar 19 '10 at 21:06
  • 3
    @peterchen: That's not an auto-implemented property. – Brian Mar 19 '10 at 21:06
  • @Brian: that is not a very helpful answer ;) - As I understand, readonly declares a field, so you lose the ability to modify the getter later without breaking the interface. – peterchen Mar 20 '10 at 06:25
  • 1
    Mods: Dupe with: http://stackoverflow.com/questions/1050761/is-it-possible-to-force-an-auto-property-to-use-a-readonly-backing-field and http://stackoverflow.com/questions/1536691/is-there-a-way-to-make-readonly-not-just-private-automatic-properties – Loren Pechtel Sep 15 '12 at 03:49
  • 1
    @Loren: My question (and answers to it) is upvoted more than these two in summary. – abatishchev Sep 16 '12 at 06:54
  • 2
    @abatishchev: Then perhaps theirs should be merged into yours. I ran into the issue and found Google hits 1, 2 & 3 were three questions here! – Loren Pechtel Sep 16 '12 at 15:03

7 Answers7

105

The answer below was written back in 2010. In C# 6 (released in 2015) you can write read-only automatically-implemented properties:

// This can only be assigned to in a constructor
public int Foo { get; }

You're absolutely right. Properly read-only automatically implemented properties are currently impossible. Making the setter private isn't the same thing, regardless of what some books and MSDN might say :)

If I ruled the world, this would not be the case. When I see some of the language designers at NDC 2010 in June (please come along!) I intend to try to persuade, bribe, cajole and generally make a nuisance of myself until they agree. It's just one wafer-thin feature, after all.

Looking at that MSDN article, the text itself doesn't say that it creates a read-only automatic property. It creates an immutable type using an automatic property, and that's correct. The only problematic bits are the comments saying

// Read-only properties.

... which are definitely wrong. The framework agrees with us:

var prop = typeof(Contact).GetProperty("Name");
Console.WriteLine(prop.CanWrite); // Prints True
Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    One *wafer-thin* feature translates into many person-weeks of work: http://blogs.msdn.com/ericlippert/archive/2003/10/28/53298.aspx – Brian Mar 19 '10 at 21:05
  • @Brian: That's why I'm going to have to persuade, bridge, cajole etc :) But compared with many other features, I believe this really *would* be small. – Jon Skeet Mar 19 '10 at 21:14
  • 27
    You don't have to convince us that it's a good idea; we know its a good idea. The questions are (1) is this the best possible feature we can do given the time and money budget that we have, and (2) can we spend that budget on solving some more general, more difficult, less "thin" aspect of immutability, of which immutable props are a simple special case? Every narrow "special purpose" feature we add increases the complexity of the grammar; we want to make sure that we're getting good value going forward for that additional complexity. – Eric Lippert Mar 19 '10 at 22:23
  • 17
    @Eric: Understood on all fronts - and any attempt to solve the wider immutability issue would be very welcome indeed. I should probably point out to others that Eric has patiently listened to this feature request from me in just about every communication medium known to man :) There's one *good* thing about it being painful to add features, mind you: it makes it harder for an imaginative team to add so many features that us mortals can't keep up. – Jon Skeet Mar 20 '10 at 07:03
  • Just interface with the existing Auto-Implementation method(s), but skip the setter creation **and** continue to disallow declaration initialization for ReadOnly Properties. The only difficulty is if you allow declaration initialization. The assignment operator and value would have to be magically transported off the declaration, and onto the backing field. There are too many problems to list in a single Comment regarding that... So if we wanted an Auto-Implemented ReadOnly Property which is auto-initialized to Type-Default, it's simple! But Allowing declaration initialization is impossible. – Suamere Jan 03 '14 at 17:51
  • So anyway... even though this discussion has gone on a long time, and I'd still personally love to see it, you can imagine the kind of awkward stares VisualStudio would receive if they had an awkward property declaration that you couldn't initialize inline. It's too alien to the concepts that currently stand. Also, it would only work for VB, which makes it more awkward. So... I'd vote for it, but wouldn't expect it to ever get done. – Suamere Jan 03 '14 at 17:54
  • @Suamere: Be patient. We'll see what might happen for C# 6 :) – Jon Skeet Jan 03 '14 at 17:57
  • You may want to update this answer now that C# 6 is close enough to being released that it is unlikely they will remove the Auto implemented read only property. – Scott Chamberlain May 17 '15 at 02:06
  • @JonSkeet what is a readonly auto-property generated to? Is the underlying field marked as `readonly`? – Shimmy Weitzhandler Nov 15 '15 at 10:28
  • 1
    @Shimmy: Yes, I believe so. – Jon Skeet Nov 15 '15 at 12:11
  • @JonSkeet Thanks. Just out of curiosity, how do you determine whether a `FieldInfo` is `readonly`? – Shimmy Weitzhandler Nov 15 '15 at 14:21
  • 1
    @Shimmy: Use `FieldInfo.IsInitOnly`. – Jon Skeet Nov 15 '15 at 14:52
  • I'm not sure I understand this paragraph: "If I ruled the world..." - Do you mean you wouldn't allow the use of `{ get; }`? – Obsidian Phoenix Jan 26 '16 at 13:25
  • @ObsidianPhoenix: No, that was referring to the time at which it wasn't possible... it was in the section of the answer that was written back in 2010. I was saying I wanted precisely the feature which exists in C# 6. – Jon Skeet Jan 26 '16 at 13:46
  • Ah ok. I'm with you now - As someone who much prefers private autoprops over member variables, its a pretty cool feature - tended not to use readonly before now. – Obsidian Phoenix Jan 26 '16 at 14:04
  • `public int Foo { get; }` can also be assigned outside constructor: `public int Foo { get; } = 1;` for example. – Second Person Shooter Jun 18 '22 at 20:39
  • 1
    @xport: That's true now - it wasn't when read-only automatically implemented properties were first introduced. – Jon Skeet Jun 18 '22 at 21:09
9

The property is read-only outside the Foo class. I think that's what article is getting at.

But it's not the same as marking a variable with the readonly keyword.

Dave New
  • 38,496
  • 59
  • 215
  • 394
kervin
  • 11,672
  • 5
  • 42
  • 59
6

It's confusing. You should differentiate read-only to the c# readonly (what the keyword means).

  • read-only: they mean that no one outside can write to it directly, only read.
  • C# readonly: you can only write to it in the constructor, then never more.
Samuel Carrijo
  • 17,449
  • 12
  • 49
  • 59
4

No, it's not possible to make an auto-implemented property readonly. For the page you linked:

with auto-implemented properties, both a get and set accessor are required

A read-only property has NO set accessor.

A property without a set accessor is considered read-only

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
3

Private set is not the same as readonly.

Similar to methods or fields, the private keyword makes the visibility of the setter available to only the class itself. Other objects cannot use the setter, but methods of the class itself can call it freely. Hence your test code compiles and works fine.

It appears to external objects as a readonly property, but it isn't read-only in the true definition.

Dave New
  • 38,496
  • 59
  • 215
  • 394
womp
  • 115,835
  • 26
  • 236
  • 269
1

The ReadOnly keyword, in C# and VB, do the same thing when applied to a field. They make it so that field is only assignable during static initialization (if it is marked as a static/shared field) or during the constructor.

C# does not utilize the readonly keyword for anything else.

The ReadOnly keyword in VB takes on a different meaning when applied to a Property. In this case, it simply means that there is no acceptable way to assign to the Public property (internally, the backing field can be modified other internal code, of course).

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
1

It is not possible to create a readonly auto-implemented property. If you try to compile a class with an auto-implemented property you will get this error if it doesn't have both get and set:

'ProjectName.ClassName.Property.get' must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors.

With the sentence begining with 'Automatically' being the part of the error we are concerned with.

Dave New
  • 38,496
  • 59
  • 215
  • 394
Jose Alava
  • 61
  • 1
  • 1