Init + private set accessors on the same property?

Viewed 4004

Is it possible to use a public init accessor and a private setter on the same property?

Currently I get error CS1007 "Property accessor already defined".

public record Stuff
{
    public int MyProperty { get; init; private set; } // Error

    public void SetMyProperty(int value) => MyProperty = value;
}

var stuff = new Stuff
{
    MyProperty = 3, // Using the init accessor
};

stuff.SetMyProperty(4); // Using the private setter (indirectly)

My best guess would be to use a private member variable, a property for that variable with get and init accessors (not auto-implemented) and the setter member function. Can it be done more easily?

3 Answers

Similar to specifying a constructor to initialize your value, you can use a private backing field so that you can still take advantage of the init logic and allow initialization without a specific constructor

public record Stuff
{
    private int _myProperty;

    public int MyProperty { get => _myProperty; init => _myProperty = value; }

    public void SetMyProperty(int value) => _myProperty = value;
}

var stuff = new Stuff
{
    MyProperty = 3 // Using the init accessor
};

stuff.SetMyProperty(4); // Using the private setter (indirectly)

No you can not. The init keyword was added in an attempt to make immutable properties on objects.

So if you have the record:

public record Stuff
{
    public int MyProperty { get; init; } // This can not be changed after initialization
}

MyProperty can only be set during the initialization of your record.

If you want your property to be mutable then you use the set accessor instead of init.

public record Stuff
{
    public int MyProperty { get; set; } // This can
}

As @Jerry's answer you can not use both setters. That is to do with the mutability of the record/object.

If you want to have private seters and some initialization logic also, the way I use is constructors:

public record Stuff
{
    public Stuff(int myProperty)
    {
        MyProperty = myProperty;
    }

    public int MyProperty { get; private set; }

    public void SetMyProperty(int value) => MyProperty = value;
}

var stuff = new Stuff(3);
stuff.SetMyProperty(4);

It is all about domain requirements.

  • Does Stuff.MyProperty needs to be publicly modifiable?
  • If it is, what would be the default value of that property, when Stuff instance is initialized? Does domain expects a default value?

etc..

Related