How to Implement a Read Only Property

How to implement a read only property

C# 6.0 adds readonly auto properties

public object MyProperty { get; }

So when you don't need to support older compilers you can have a truly readonly property with code that's just as concise as a readonly field.


Versioning:

I think it doesn't make much difference if you are only interested in source compatibility.

Using a property is better for binary compatibility since you can replace it by a property which has a setter without breaking compiled code depending on your library.

Convention:

You are following the convention. In cases like this where the differences between the two possibilities are relatively minor following the convention is better. One case where it might come back to bite you is reflection based code. It might only accept properties and not fields, for example a property editor/viewer.

Serialization

Changing from field to property will probably break a lot of serializers. And AFAIK XmlSerializer does only serialize public properties and not public fields.

Using an Autoproperty

Another common Variation is using an autoproperty with a private setter. While this is short and a property it doesn't enforce the readonlyness. So I prefer the other ones.

Readonly field is selfdocumenting

There is one advantage of the field though:

It makes it clear at a glance at the public interface that it's actually immutable (barring reflection). Whereas in case of a property you can only see that you cannot change it, so you'd have to refer to the documentation or implementation.

But to be honest I use the first one quite often in application code since I'm lazy. In libraries I'm typically more thorough and follow the convention.

Set a read only property defined in a interface within a concrete class

This doesn't have anything to do with the interface, you're just declaring the property incorrectly. In C# 6, you can create a read-only property like this:

public class Person : IPerson
{
public Person()
{
Name = "Person";
}

public string Name { get; }
}

In earlier versions, you can use a read-only backing field which you can set:

public class Person : IPerson
{
private readonly string _name;

public Person()
{
_name = "Person";
}

public string Name
{
get { return _name; }
}
}

Note that the interface only requires the property has a getter, the implementation doesn't have to be read-only. You could add a setter if you had reason to modify the value:

public class Person : IPerson
{
public Person()
{
Name = "Person";
}

public string Name { get; set; }
}

The setter could be private if you only needed to be able to change the value from within the class.

How can I change a readonly property in TypeScript?

There are actually 3 ways I know of. If you have a class like this:

class GraphNode {
readonly _parent: GraphNode;
add(newNode: GraphNode) { /* ...etc... */ }
}
var node = new GraphNode();

In the add() function you could do either:

  1. newNode[<any>'_parent'] = this; - Works, but BAD IDEA. Refactoring will break this.

    Update: Seems newNode['_parent'] = this; will work just fine now without <any> in newer versions of TypeScript, but refactoring will still break it.

  2. (<{_parent: GraphNode}>newNode)._parent = this; - Better than 1 (not the best), and although refactoring breaks it, at least the compiler will tell you this time (since the type conversion will fail).
  3. BEST: Create an INTERNAL interface (used by yourself only):

    interface IGraphObjectInternal { _parent: GraphNode; }
    class GraphNode implements IGraphObjectInternal {
    readonly _parent: GraphNode;
    add(newNode: GraphNode) { /* ...etc... */ }
    }

    Now you can just do (<IGraphObjectInternal>newNode)._parent = this; and refactoring will also work. The only caveat is that if you export your class from a namespace (the only reason to use an internal interface IMO) you'll have to export the interface as well. For this reason, I sometimes will use #2 to completely lock down internals where there's only one place using it (and not advertise to the world), but usually #3 if I need to have many properties to work with referenced in many other locations (in case I need to refactor things).

You may notice I didn't talk about getters/setters. While it is possible to use only a getter and no setter, then update a private variable, TypeScript does not protect you! I can easily do object['_privateOrProtectedMember'] = whatever and it will work. It does not work for the readonly modifier (which was in the question). Using the readonly modifier better locks down my properties (as far as working within the TypeScript compiler is concerned), and because JavaScript doesn't have a readonly modifier, I can use various methods to update them with workarounds on the JavaScript side (i.e. at runtime). ;)

Warning: As I said, this only works within TypeScript. In JavaScript people can still modify your properties (unless you use getters only with non-exposed properties).

Update

Since typescript 2.8 you can now remove the readonly modifiers:

type Writeable<T> = { -readonly [P in keyof T]: T[P] };

and also the optional modifier:

type Writeable<T> = { -readonly [P in keyof T]-?: T[P] };

More here: Improved control over mapped type modifiers

Implementing read-only properties with { get; }

Your code is valid for C# 6, which comes with Visual Studio 2015. It is not valid for previous versions of the language or Visual Studio. Technically, you can install an old pre-release version of Roslyn in VS 2013 but it isn't worth the trouble now that VS 2015 was released.

For this problem to occur, either you are using the wrong version of Visual Studio to compile C# 6 code, or you are trying to compile your code from the command line using the wrong development environment -ie, your PATH points to the old compiler. Perhaps you opened the 'Developer Command Prompt for 2013' instead of 2015?

You should either compile your code using Visual Studio 2015, or ensure your path variable points to the latest compiler.

If you have to use Visual Studio 2013 or older, you'll have to change your code to use the older syntax, eg:

public readonly string _colour;

public string Colour { get {return _colour;}}

public Apple(string colour)
{
_colour=colour;
}

or

public string Colour {get; private set;}

public Apple(string colour)
{
Colour=colour;
}

Note that the second option isn't truly read-only, other members of the class can still modify the property

NOTE

You can use Visual Studio 2015 to target .NET 4.5. The language and the runtime are two different things. The real requirement is that the compiler must match the language version

Read-Only Property in C# 6.0

Your example is using string constants which can't show all the possibilities. Look at this snippet:

class Foo
{
public DateTime Created { get; } = DateTime.Now; // construction timestamp

public int X { get; }

public Foo(int n)
{
X = n; // writeable in constructor only
}
}

Read only properties are per-instance and can be set from the constructor. Very different from a const field whose value must be determined at compile time. The property initializer is a separate feature and follows the rules and limitations of field initializers.

How to override readonly property in Swift subclass, make it read-write, and assign to superclass?

super.inputAccessoryViewController is not settable.

Your overridden implementation in the subclass, self.inputAccessoryViewController is.

By adding a setter to the property in a subclass, you don't automatically also add the same thing in the superclass. What's in the subclass stays in the subclass.

So it's not that you can't override a property by adding a setter, you just can't set this here:

override var inputAccessoryViewController: UIInputViewController? {
get { super.inputAccessoryViewController }
set { super.inputAccessoryViewController = newValue }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

You can do other things, like:

override var inputAccessoryViewController: UIInputViewController? {
get { super.inputAccessoryViewController }
set { print("I just go set to \(newValue)") }
}

But that's not very useful. What you want is probably:

private var myInputAccessoryController: UIInputViewController?

override var inputAccessoryViewController: UIInputViewController? {
get { myInputAccessoryController }
set { myInputAccessoryController = newValue }
}

What is the definition of a read-only property in JavaScript? What does it mean?

A read-only property means it cannot be overwritten or assigned to. Any such assignment will silently do nothing in non-strict mode. E.g.:

var obj = {};
Object.defineProperty(obj, 'property', {value: 123, writeable: false})

// Assign 456 to obj.property using the . syntax, but it's still 123
obj.property = 456;
console.log(obj.property);

// Assign 789 to obj.property using the [] syntax, but it's still 123
obj['property'] = 789;
console.log(obj['property']);

Prevent assigning to readonly property

There is not a way to fail the compilation currently. There are a few things you can do alternatively:

  • Use a lint rule
  • Use the technique suggested here which is pretty awkward: Disable allowing assigning Readonly types to non-readonly types
  • Be satisfied with a run-time error using Object.freeze

How to force update on a read only property?

when you set the value of Amount or Price you can raise mulitple PropertyChanged events

public class Sale : BaseViewModel
{
private double amount;
private double price;

public double Amount
get { return amount; }
set { SetProperty(ref amount, value);
this.OnPropertyChanged("Total"); }

public double Price
get { return price; }
set { SetProperty(ref price, value);
this.OnPropertyChanged("Total"); }

public double Total { get { return Amount * Price; } }
}


Related Topics



Leave a reply



Submit