4

I am often writing classes that create a new object in a property getter, but I have read this is not necessarily best practice. Eg:

public class Board
{
    public float Width { get; }
    public float Height { get; }
    public CGSize Size { get { return new CGSize(this.Width, this.Height); } }

    public Board(float width, float height)
    {
        this.Width = width;
        this.Height = height;
    }
}

Is there anything wrong with that?

See here: Is object creation in getters bad practice? where various upvoted people suggest it is bad practice, eg: "Yes, it is bad practice. Ideally, a getter should not be changing or creating anything". And that reading a property twice should produce identical results (whereas creating a new object will be different each time.)

(I note that in C# the System.Drawing.Rectangle class has a Size property that does return a new object each time.)

Bbx
  • 3,184
  • 3
  • 22
  • 33
  • 2
    What is CGSize? If it's a value type, then it's *definitely* fine. If it's a reference type, it's not ideal - but not truly awful either, IMO. – Jon Skeet Feb 04 '18 at 11:35
  • @Jon Skeet: It's a Xamarin struct based on the CGSize struct in iOS. – BoltClock Feb 04 '18 at 11:40
  • 1
    Right. In which case it's not creating a new *object* at all, so it's fine. – Jon Skeet Feb 04 '18 at 11:41
  • OK thanks. Well it's a struct, so value type. And what if I want to use a reference type. What is the best solution then? – Bbx Feb 04 '18 at 11:42
  • 1
    Side-note: this is an ideal example of where an expression-bodied member helps: `public CGSize Size => new CGSize(Width, Height);` – Jon Skeet Feb 04 '18 at 11:42
  • 2
    @Bbx: Then you should describe an actual situation where you'd want to do that, with details of the type involved. Context is very important - don't look for simple rules that cover every scenario. – Jon Skeet Feb 04 '18 at 11:43
  • OK, thanks for the very prompt answers (and tip about expression-bodied members). I can't find an actual example where I've needed to use reference types like that, so value types is OK is the answer I was looking for. – Bbx Feb 04 '18 at 11:51
  • The question pre-supposes that Width and Height are used as if they were [`readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly). Might as well make them so. – Tom Blodget Feb 04 '18 at 17:26
  • 1
    They are readonly. Having not "set" means it's a readonly property (a feature added in C#6, I think) – Bbx Feb 04 '18 at 20:57

1 Answers1

3

Creating a new object is a good defensive strategy to prevent modifications of your object's internals.

However, it should be applied only when the object that you are returning is a mutable, and is not a struct (which should be immutable anyway [why?]).

CGSize is a struct, so you are creating a new value-typed object here. This is exactly what you should do when you do not store the Size.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523