2

I've been going through an app I'm developing and it makes heavy use of immutability. I've just discovered getter-only automatic properties are in C# 6.0 so I'm refactoring to use those. I've hit one possible question-mark though, which is where I'm exposing private IList<T> objects as ReadOnlyCollection<T> through public properties, to avoid the possibility of them being casted back to their original List<T> object, e.g.

private IList<string> tags = new List<string>();

public IEnumerable<string> Tags => new ReadOnlyCollection<string>(this.tags);

Is there any way to use auto-properties with this type of customised getter?

James
  • 1,028
  • 9
  • 20
  • 1
    It can't be an auto-property because you have code in the getter. The question is what is wrong? Why do you need an auto-property? – Sinatr Aug 30 '16 at 11:17
  • It doesn't *have* to be an auto-property, I just wondered if it could be - to align with the general code style. – James Aug 30 '16 at 11:18
  • *"with the general code style"* - there is no such thing as using only auto-properties or only full properties. Btw, calling getter only property *immutable* feels wrong if it expose **new instance** of something every time. Consider to initialize that property in constructor and then you indeed can use auto property (with getter only). – Sinatr Aug 30 '16 at 11:21
  • @Sinatr: I have taken the liberty to include (and flesh out) your comment in my answer. – Heinzi Aug 30 '16 at 11:25

1 Answers1

6

Unfortunately, no. Auto-properties are a shortcut for properties which don't have customized getters or setters.


As a side note: As Sinatr correctly mentions in the comments, you are creating a new instance of the ReadOnlyCollection on every property invocation. That is untypical for a property. Consider returning the same instance every time instead:

private IList<string> tags = new List<string>();
public IEnumerable<string> Tags { get; }

public MyClass()
{
    Tags = new ReadOnlyCollection<string>(this.tags);
}

This works because ReadOnlyCollection reflects changes made to the underlying collection:

An instance of the ReadOnlyCollection<T> generic class is always read-only. A collection that is read-only is simply a collection with a wrapper that prevents modifying the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes.


Note: The constructor is required: C# does not allow field initializers to reference other instance fields, since the compiler might rearrange the initialization order. In VB.NET, where fields are initialized in the order in which they appear, this could be written as follows:

Private tagList As New List(Of String)()
Public ReadOnly Property Tags As IEnumerable(Of String) = New ReadOnlyCollection(Of String)(tagList)
Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • You say no, but your suggested improvement says yes to me. ;) Of course it's not semantically identical, but for OP's specific case I think you could as well have said 'yes, like this' – Joren Aug 30 '16 at 11:31
  • @Joren: Even with the improvement, he still needs the explicit "backing field": `private IList tags = new List();` - we now have an explicit one *and* an implicit one. I have added the second line to my answer to emphasize this. – Heinzi Aug 30 '16 at 11:34
  • You're right, I guess I misunderstood the question. – Joren Aug 30 '16 at 11:35
  • This makes sense, and good spot re creating a new instance of `ReadOnlyCollection` each time the property is called. The only downside of the initialiser you put in your answer is it can only reference static members or constants, not instance variables; so I'm not sure how to offer up a single instance short of initialising the public `IEnumerable` in a constructor. – James Aug 30 '16 at 12:51
  • @James: This took me by surprise, since both VB.NET and Java allow instance field references in field initializers. Well spotted, I have updated my answer. – Heinzi Aug 30 '16 at 14:15