1

Wrapping a struct or class field in a property forces all accesses to that field to go through "getter" and "setter" methods. This allows for the possibility of adding logic for validation, lazy initialization, etc. Further, in the case of class fields, it allows for the possibility that one might have logic which applies to some instances but not others; if the properties are not virtual, it may be difficult to implement such logic efficiently (e.g. one would might have to define a static VerySpecialInstance and have the property getter say if (this == VerySpecialInstance) GetSpecialProperty(); else GetOrdinaryProperty();) but it could be done.

If, however, the semantics of a struct (e.g. System.Drawing.Point) dictate that a particular read-write property may be written with any value which is legal for its type, writing will have no side effect other than to change its value, it will always return the last value written (if any), and if not written it will read as the default value for its type; and if code which uses the type will likely rely upon such assumptions, I'm unclear on what possible benefit would be served by using a read-write property rather than a field to hold the value.

The fact that Microsoft uses properties rather than fields for things like Point.X etc. has historically caused confusion since MyList[3].X = 4; would be translated to MyList[3].Set_X(4), and without looking inside the definition of Set_X it's not possible to tell whether that method would achieve its desired effect without changing any fields of the struct in question; today's C# compiler will guess that it wouldn't work, and will forbid that construct even though there are some struct types where property setters would in fact work just fine. If X been a field rather than a property, and if Microsoft had said that the two safe ways to mutate a struct are either to access the fields directly or to pass the struct as a ref parameter to a mutating method (which, if it's a static method of the struct type, could access public fields), such guesswork would not be necessary.

Given that using exposed struct fields rather than read-write properties improves both performance and semantic clarity, what reasons exist to make struct fields private and wrap them in properties? Data binding requires properties, but I don't think it works with structure types anyway (if one makes a copy of a struct and then sets some property of the original to one value and the corresponding property of the duplicate to another, what value should be reported to the bound object?) Are there some benefits of struct properties of which I'm unaware?

Personally, I think the 'ideal' struct in many cases would simply be a list of exposed public fields, and a constructor whose parameters are simply the initial values of those fields, in order. Such a struct would offer optimal performance and predictable semantics (behaving identically to all other such structs, aside from the types and names of the fields). Is there any reason to favor read-write properties in cases where there isn't anything they could do anything other than simply read and write an underlying field?

supercat
  • 77,689
  • 9
  • 166
  • 211

2 Answers2

1

Don't see any benefit on immutable struct of using read/write properties, except point you wrote about: wrapping the logic inside setter and/or getter of the property, and maintaining general guideline across your code base (benefit for maintainance and readability point of view) .

I personally when define a struct almost always use raw public fields and no properties, for simplicity and easy consumption of my type (for the problems on immutable types you wrote already in question)

Hope this helps.

Tigran
  • 61,654
  • 8
  • 86
  • 123
  • I understand the 'maintaining a general guideline' notion for class fields, since there are many ways one might want to add behavior (such as data binding) to a field-like characteristic of a class. The fact that fields can be used in ways that properties cannot may be seen as an argument for or against wrapping class fields. My question is whether there's any logical reason to extend such a guideline to struct fields, given that structs and classes are different. – supercat Aug 17 '12 at 16:18
  • @supercat: As I said, I personally, when create a `struct`, use fields, so I personally in `struct` don't see a benefit of using a property. – Tigran Aug 17 '12 at 16:21
  • Thanks for writing. I wonder whether anyone else can articulate the contrary viewpoint. – supercat Aug 17 '12 at 20:32
  • @supercat: in general not, cause it's a generally accepted guideline (to have a properties I mean). But one time I was watching a talk of one guy from `CLR` team, that says that `properties` have thier overhead, minimum but have. It's kind of out of the subject of this question, but just to mantion that even from MS, sometime violate the basic guideline principles is ok :) – Tigran Aug 17 '12 at 20:38
  • The overhead of using properties is often small, but can sometimes be enormous. If `biz` is a non-read-only field of a a very large and deeply-nested struct type whose fields are exposed at every layer, a read or write of integer field `biz.baz.boz.moe.larry.curly` will simply be an integer load or store. By contrast, if `baz` and `curly` were properties, reading `biz.baz.boz.moe.larry.curly` would entail copying everything in `biz.baz`, then everything in `biz.baz.boz`, then `biz.baz.boz.moe` and `biz.baz.boz.moe.larry`. Big structures can be efficient when using fields, but not properties. – supercat Aug 17 '12 at 22:05
1

Rico Mariani wrote a good MSDN blog article on this very topic.

Reasons to use public fields rather than getters and setters include:

  1. There are no values the field cannot be allowed to have.
  2. The client is expected to edit it.
  3. To be able to write things such as object.X.Y = Z.
  4. To making a strong promise that the value is just a value and there are no side-effects associated with it (and won't be in the future either).

Some people find this very controversial. I suspect this is because the case listed rarely or never come up in the kind of software they write, but they don't realise that in other application areas they come up a great deal.

(This is a copy of an answer I provided here, but I thought the information is useful enough to be repeated here.)

Community
  • 1
  • 1
Ian Goldby
  • 5,609
  • 1
  • 45
  • 81
  • I think the controversy stems from the IMHO misguided idea that it's useful to regard everything is an "object", rather than recognizing that a structure-type definition actually defines a heap object type (which derives from `ValueType` and thus `Object`) and a storage location type (which doesn't derive from anything but can be converted to or from the heap object type). If one expects a bunch of variables stuck together with duct tape to behave like a heap object, one will be disappointed and confused. But if what what's *needed* is a bunch of variables stuck together with duct tape... – supercat Jul 09 '15 at 15:48
  • ...trying use a bunch of variables stuck together with duct tape to emulate a heap object which is trying to serve the purpose of a bunch of variables stuck together with duct tape is apt to be less efficient than using a bunch of variables stuck together with duct tape *as* a bunch of variables stuck together with duct tape. – supercat Jul 09 '15 at 15:50
  • Ironically, I'd say the database scenario would be an example where structures could have an advantage. If a `GetRecord` function returns a directly mutable class object, it may be unclear whether and how changes to that object will be applied to the database. If it returns a `LiveRecord` object which exposes methods `RecordContents GetContents()`, `void UpdateContents(RecordContents)`, and `UpdateResult TryUpdateContents(RecordContents)`, and `RecordContents` is a `struct`, then it would be clear that changes made to the `RecordContents` structure would be applied to the database when... – supercat Jul 10 '15 at 15:06
  • ...and only when code called an update method. Code which wanted to manipulate the contents of one record speculatively, or use them as a template for another record, could freely do so without having to worry about whether such actions would modify the underlying database, since there would be no mechanism by which they could do so. – supercat Jul 10 '15 at 15:08
  • BTW, with regard to "no illegal values", I think I would instead say "Not expected to validate values". If one has a `ScrollBarState` struct which contains fields `Minimum`, `Maximum` and `Value`, such a struct may be rejected by a `SetState` method when `Value` is not in the range from `Minimum` to `Maximum`, but putting the validation in the code which receives the structure may allow cleaner code than requiring the type to maintain the invariant that `Value` always be between `Minimum` and `Maximum`. – supercat Jul 10 '15 at 15:12