.NET Forum / Languages / C# / March 2008
Get/Set vs Public Variables
|
|
Thread rating:  |
JB - 04 Feb 2008 13:48 GMT I was always taught in C++ that using public variables was a bad idea, which i could understand, so some generic get/set methods were usually wrote to access the data.
Now in C# I'm just curious about properties.
Say I have
class SomeClass { private in data public int Data() { get {return data;} set {data=value;} }
vs
class SomeClass { public int data }
Most seem to prefer using the properties approach, but not yet being a pro at C# i'm struggling to find a difference. In effect they both seem exactly the same. I can see how using properties would be useful if you need to apply some sort of extra processing before setting the value, or for creating read-only/write-only variables.
But for the very basic, is there any reason i should be using properties instead of public variables? In fact for the basic is there any difference in execution time between get/set and direct access?
Jon Skeet [C# MVP] - 04 Feb 2008 13:54 GMT > I was always taught in C++ that using public variables was a bad idea, > which i could understand, so some generic get/set methods were usually > wrote to access the data. It's exactly the same in C#. I don't really see how you can understand why it's a good thing in C++, but not in C#.
> Most seem to prefer using the properties approach, but not yet being a > pro at C# i'm struggling to find a difference. > In effect they both seem exactly the same. No, they don't. Exposing the fields is exposing the *implementation* - how the data is stored. Exposing the properties just says "I have this state, but you're not allowed to know how it's stored".
The underlying storage shouldn't be part of the public API - the fact that data *is* stored (or computed, or generally made available) *is* part of the public API.
> But for the very basic, is there any reason i should be using > properties instead of public variables? Yes - to avoid exposing the implementation.
> In fact for the basic is there any difference in execution time > between get/set and direct access? Not after JIT inlining.
Jon
Paul Werkowitz - 05 Feb 2008 21:14 GMT Am Mon, 4 Feb 2008 05:54:37 -0800 (PST) schrieb Jon Skeet [C# MVP]:
>> I was always taught in C++ that using public variables was a bad idea, >> which i could understand, so some generic get/set methods were usually >> wrote to access the data. > > It's exactly the same in C#. I don't really see how you can understand > why it's a good thing in C++, but not in C#. First, more tahn 90% of properties I saw in my life are simple setters and getters without any useful functionality.
Second, chances are really low that a construct like
class Person { string name; string firstname; }
EVER will need any functionality in getters and setters for the two string fields.
So, why is it a bad idea to expose them directly to clients?
- dirty management for business objects? No. This requires to explicitely call some function (IPropertyChanged) in the setter, only for that purpose. There are better ways.
- Binding to external code? No. When someone ref-binds to a public variable and this is later changed to a property, we must change the statement and recompile. Big deal? IMO, no.
- Databinding etc? No. It is a conceptual lack of WinForms (and WPF) databinding that it can bind only to properties and not to variables. Technicaly, it is no problem to include variables in binding. But LINQ alleviates most of that.
Of course, there are situations where this is sinply wrong. If I must anticipate the situation that my implementation might change, I definitely am better off with properties. But for > 90% of all classes with data members this is NOT the case. And if I make a mistake here, the cost is low - mostly recompilation, and some syntax errors. Definitely not worth to make everything private.... - at least until auto-properties were invented.
Greetz Paule
Jon Skeet [C# MVP] - 05 Feb 2008 21:20 GMT <snip>
> Of course, there are situations where this is sinply wrong. If I must > anticipate the situation that my implementation might change, I definitely > am better off with properties. But for > 90% of all classes with data > members this is NOT the case. And if I make a mistake here, the cost is low > - mostly recompilation, and some syntax errors. Definitely not worth to > make everything private.... - at least until auto-properties were invented. If you want to ignore best practice, that's your call. I'll stick to exposing an API which doesn't expose the implementation.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Paul Werkowitz - 06 Feb 2008 15:15 GMT Am Tue, 5 Feb 2008 21:20:43 -0000 schrieb Jon Skeet [C# MVP]:
> If you want to ignore best practice, that's your call. Of course. At least until someone can show arguments why "always use properties and make data private" is "best practice".
I gave some arguments why IMO this is not so, but until now you did not give any reasoning.
Looking forward to hearing....
Greetz Paule
Jon Skeet [C# MVP] - 06 Feb 2008 15:23 GMT > > If you want to ignore best practice, that's your call. > [quoted text clipped - 5 lines] > > Looking forward to hearing.... Well, you've already dismissed the important reasons as being unimportant to you: 1) Discriminating between implementation and API 2) Binary compatibility of old code running against new implementation 3) Source compatibility of old code compiling against new implementation
Those are all good enough reasons for me, but apparently not enough for you.
In my experience that's okay if you're just messing around or never see multiple versions of the same code - but doesn't work in most commercial environments.
Jon
Paul Werkowitz - 09 Feb 2008 16:02 GMT Am Wed, 6 Feb 2008 07:23:00 -0800 (PST) schrieb Jon Skeet [C# MVP]:
> Well, you've already dismissed the important reasons as being > unimportant to you: > 1) Discriminating between implementation and API > 2) Binary compatibility of old code running against new implementation > 3) Source compatibility of old code compiling against new > implementation and, not to forget the new dependency properties etc. of WPF, to add to the list.
If these reasons are important (or only one of them, mainly the first) - yes, then we should use properties. But: for most objects, these requirements are not si important. More than 90% of the property implementations I have seen are simple setters and getters without any functionality, and never will need any. I still have the opinion that these are superfluous things.
I agree that there are situations where they are useful, or even necessary. You named some.
At the moment, if I want to use databinding for example, I have to use properties on my business object. The properties are all empty, because my validation etc. is done otherwise. (Most of it could not be done in setters anyway, because validity of one data element heavily depends on other data elements in the same object). Fortunately, this is alleviated with the auto-property feature of .NET 3
> Those are all good enough reasons for me, but apparently not enough > for you. So, you access all of your data in every object of ll your applications only via properties. OK - and how many of theses properties are really empty? And will probably stay empty during the lifetime of the product?
Greetz Paule
Jon Skeet [C# MVP] - 09 Feb 2008 19:09 GMT <snip>
> > Those are all good enough reasons for me, but apparently not enough > > for you. > > So, you access all of your data in every object of ll your applications > only via properties. OK - and how many of theses properties are really > empty? And will probably stay empty during the lifetime of the product? Many - but I don't need to worry about binary or source incompatibilities if I *do* need to do anything. Where's the harm? Writing a property takes seconds with appropriate templates etc. The only real downside IMO is that the code is then there, potentially being obtrusive in your class. That's reasonably easily solved with regions.
With C# 3 there's even less reason not to use properties, as automatic properties let you follow best practices with just a single line of code.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Scott Roberts - 05 Feb 2008 21:44 GMT > First, more tahn 90% of properties I saw in my life are simple setters and > getters without any useful functionality. Hmmm, I've not had the same experience.
> Second, chances are really low that a construct like > [quoted text clipped - 6 lines] > EVER will need any functionality in getters and setters for the two string > fields. So "name" and "firstname" can hold an unlimited number of characters? I guess that's fine if you don't use a DB or your DB fields allow unlimited characters. In practice, most strings have a maximum size. I guess you could validate it later (like before saving) but I personally prefer to avoid invalid states rather than report invalid states.
Paul Werkowitz - 06 Feb 2008 15:24 GMT Am Tue, 5 Feb 2008 15:44:16 -0600 schrieb Scott Roberts:
>> Second, chances are really low that a construct like >> [quoted text clipped - 8 lines] > > So "name" and "firstname" can hold an unlimited number of characters? No, of course not. But it is the responsibility of the data provider to ensure the condition. The setter can only throw an exception .... a thing to avoid, frankly.
It is better to have the data provider ensure proper data states. For example, if the data comes from a GUI, it would be better to implement the length check in the Edit-Field, and alert the user that no more chars can be input.
Conclusion: Information about data validity (data model) are needed in several placed, e.g. in the GUI, sometimes in the DAL etc. But not in the Person class.
[snip]
> In practice, most strings have a maximum size. I guess you could > validate it later No! Definitely not! "Later" would be far too late! I do not wand my clients to comeplete pages of data and when they press Save, give an error message...
Greetz Paule
Scott Roberts - 06 Feb 2008 15:39 GMT > Am Tue, 5 Feb 2008 15:44:16 -0600 schrieb Scott Roberts: > [quoted text clipped - 15 lines] > ensure the condition. The setter can only throw an exception .... a thing > to avoid, frankly. I disagree. The business object should enforce business logic. The maximum length of of a field, required values, range checks, etc. are all business rules. Does the data provider arbitrarily decide the max length of a field? No, it's based on a business rule - which should obviously go in the business layer.
> It is better to have the data provider ensure proper data states. For > example, if the data comes from a GUI, it would be better to implement the > length check in the Edit-Field, and alert the user that no more chars can > be input. GUI validation is worthwhile, but it doesn't absolve the business object from the responsibility of ensuring valid data. If you rely on the "data provider" to ensure proper data states then you are spreading your business logic all over the place. Some will exist in the web GUI, some will exist in the Windows Forms GUI, some in a web service (that allows an API into the Person class), etc. This is exactly the type of thing that having a business layer is supposed to eliminate.
> Conclusion: Information about data validity (data model) are needed in > several placed, e.g. in the GUI, sometimes in the DAL etc. But not in the > Person class. Sorry, but the Person class is really the *only* place that it is needed. If you put it there then you *don't* need it anywhere else (unless you want to put some simple validation in the GUI for user convenience). If you don't do any validation in the business layer, then why even have a business layer? Just forgo the Person class and plug data directly from your GUI into the database.
> No! Definitely not! "Later" would be far too late! I do not wand my > clients > to comeplete pages of data and when they press Save, give an error > message... I agree.
Paul Werkowitz - 09 Feb 2008 16:13 GMT Am Wed, 6 Feb 2008 09:39:55 -0600 schrieb Scott Roberts:
>>> So "name" and "firstname" can hold an unlimited number of characters? >> [quoted text clipped - 3 lines] > > I disagree. The business object should enforce business logic. Of course it should! But we were talking about properties (of the BO). Thats a different thing.
Validity definitions must be near the business data, and be accessable by all agents that can change business data. So the rules should be in some form accesible by the program. MS Application Building Block (or so, forgot the name) for example, uses C#-attributes to specify validation rules.
In WPF, validation logic can be specified with the binding.
But never in setters of the business object!
>The maximum > length of of a field, required values, range checks, etc. are all business > rules. Does the data provider arbitrarily decide the max length of a field? > No, it's based on a business rule - which should obviously go in the > business layer. Absolutely. But it should not be coded in a setter. That's my point: then U cannot use it in other places!
> GUI validation is worthwhile, but it doesn't absolve the business object > from the responsibility of ensuring valid data. If you rely on the "data > provider" to ensure proper data states then you are spreading your business > logic all over the place. I did not say that the validation logic must be placed in the GUI. I said that the validation must be performed in the GUI. That is a differnet thing. Again: The Data and the rules that define validity of that data must be in one place AND must be accessible from all parties that can modify that data - e.G. the GUI.
Greetz Paule
Rene - 05 Feb 2008 23:08 GMT > Second, chances are really low that a construct like > [quoted text clipped - 6 lines] > EVER will need any functionality in getters and setters for the two string > fields. Other than for experimenting, I have never bee able to do something like you mentioned.
For example, if this was your typical business object, the name and last name properties will probably include checking for certain rules such as making sure that the last name of the person is not blank or does not exceed the characters allowed on the database.
Then you are probably going to want to add some sort of security checks where you may want to throw an exception if the user does not have the permission to change this value.
The list goes on and on. Adding business logic to your getters and setters in your bussiness objects make your application more dynamic and robust.
Cheers.
Paul Werkowitz - 06 Feb 2008 15:31 GMT Am Tue, 5 Feb 2008 17:08:34 -0600 schrieb Rene:
[snip]
> making sure that the last name of the person is not blank .... And then - how can you create such an object, that is empty? E.G. for binding to controls in a GUI that are empty? The object would be in invalid state.
Checks like you mentioned are not to be implementesd in BOs.
Greetz Paule
Scott Roberts - 06 Feb 2008 17:50 GMT > Am Tue, 5 Feb 2008 17:08:34 -0600 schrieb Rene: > [quoted text clipped - 5 lines] > invalid > state. Well, the setter is obviously not called when the object is created. If the GUI tried to put a blank value into the property an exception would occur, which is exactly what should happen.
> Checks like you mentioned are not to be implementesd in BOs. If you don't put business rules in your BOs, then what *do* you put in there?
Ben Voigt [C++ MVP] - 06 Feb 2008 23:02 GMT >> Checks like you mentioned are not to be implementesd in BOs. > > If you don't put business rules in your BOs, then what *do* you put in > there? public fields, are apparently what Paul puts in there
Paul Werkowitz - 09 Feb 2008 16:19 GMT Am Wed, 6 Feb 2008 11:50:10 -0600 schrieb Scott Roberts:
>> And then - how can you create such an object, that is empty? E.G. for >> binding to controls in a GUI that are empty? The object would be in [quoted text clipped - 4 lines] > GUI tried to put a blank value into the property an exception would occur, > which is exactly what should happen. Right. But if this happens then we have a programming error. GUI must have acces to validation rules and not allow to put invalid data into a BO. Instead, GUI should show some info to the user etc...
>> Checks like you mentioned are not to be implementesd in BOs. > > If you don't put business rules in your BOs, then what *do* you put in > there? Sorry, my wording was wrong. I meant: "... not to be implemented in setters". Business rules should of course be defined near the BO.
Greetz Paule
Rene - 07 Feb 2008 21:37 GMT Paul,
There is nothing wrong with having an object holding an invalid state. Things don't have to crash. The problem would be if you try to save the invalid object data to a database for example.
When a new object gets instantiated it could have a collection of broken rules (one of them being last name can't be blank). When the user set the value of last name to a valid name you can remove that broken rule, if the user the set the value to blank again you add the broken rule back again.
The moment the user tries to save the object into the database you can check the broken rules collection and throw an error if broken rules are found.
Having the business rules right in the getter and setter is a logical place to have them.
> Am Tue, 5 Feb 2008 17:08:34 -0600 schrieb Rene: > [quoted text clipped - 10 lines] > Greetz > Paule Marc Gravell - 07 Feb 2008 22:21 GMT Just yet another viewpoint...
Validation in the setter is perfect for things that can *never* be valid, i.e. invalid format, out-of-range, too large, etc. However, it can get tricky if your business rules cross-reference each other. The classic example is the DateTimePicker, where Min / Max / Value fight with eachother; the issue is that you place a dependency on the caller both setting the right properties *and* setting them in the right order - which can easily require a 3rd intermediary state.
In such cases, a more explicit Validate() method is useful, but I agree that this generally belongs to the business entity itself (unless it is a proxy, in which case all bets are off).
A useful model here is IDataErrorInfo; for starters, if you implement this it will *automatically* display the messages to the user in some controls (DataGridView, for example) via an error blob. And it isn't hard to hook regular bindings to it as well (a bit more manual, though; and note you need to use the indexer-variant). But more importantly: it provides a simple method your data-layer can query:
IDataErrorInfo errObj = obj as IDataErrorInfo; string errMsg; if(errObj != null && !string.IsNullOrEmpty(errMsg = errObj.Error)) { throw new DataException(errMsg); }
Although any similar "are you happy with yourself?" method would suffice ;-p (but is nice to be able to use the same code at both UI and DAL, without having to do anything special)
Marc
Paul Werkowitz - 09 Feb 2008 16:29 GMT Am Thu, 7 Feb 2008 14:21:29 -0800 (PST) schrieb Marc Gravell:
> Validation in the setter is perfect for things that can *never* be > valid, i.e. invalid format, out-of-range, too large, etc. However, it [quoted text clipped - 7 lines] > agree that this generally belongs to the business entity itself > (unless it is a proxy, in which case all bets are off). Full ack.
Paule
Paul Werkowitz - 09 Feb 2008 16:28 GMT Am Thu, 7 Feb 2008 15:37:32 -0600 schrieb Rene:
> Paul, > > There is nothing wrong with having an object holding an invalid state. > Things don't have to crash. The problem would be if you try to save the > invalid object data to a database for example. Or use it in any other context...., yes!
> When a new object gets instantiated it could have a collection of broken > rules (one of them being last name can't be blank). When the user set the [quoted text clipped - 3 lines] > The moment the user tries to save the object into the database you can check > the broken rules collection and throw an error if broken rules are found. That is a very interesting approach, and I use a variation of it for a long time. I have a isValid-Function that calculates that set of broken rules (as you named it) on the fly (does not store it). I use that on the GUI for example to provide users with appropriate feedback (yellow an red markers near controls, info panel etc.). --- But I don't need no accessors for that.
> Having the business rules right in the getter and setter is a logical place > to have them. Not necessarily. I calculate it on the fly, when needed. Caching is not necesary, and is more hassle than use. So, down to the bones, I say: I don't care whats in the object, as long as I can determine its validity state at any time I need to.
Paule
Rene - 05 Feb 2008 23:08 GMT > Second, chances are really low that a construct like > [quoted text clipped - 6 lines] > EVER will need any functionality in getters and setters for the two string > fields. Other than for experimenting, I have never bee able to do something like you mentioned.
For example, if this was your typical business object, the name and last name properties will probably include checking for certain rules such as making sure that the last name of the person is not blank or does not exceed the characters allowed on the database.
Then you are probably going to want to add some sort of security checks where you may want to throw an exception if the user does not have the permission to change this value.
The list goes on and on. Adding business logic to your getters and setters in your bussiness objects make your application more dynamic and robust.
Cheers.
Arne Vajhøj - 10 Mar 2008 02:18 GMT > First, more tahn 90% of properties I saw in my life are simple setters and > getters without any useful functionality. [quoted text clipped - 9 lines] > EVER will need any functionality in getters and setters for the two string > fields.
> - Binding to external code? No. When someone ref-binds to a public variable > and this is later changed to a property, we must change the statement and > recompile. Big deal? IMO, no. Not for small programs. But for large scale systems it can be a huge problem.
Component A and B both uses component C, component A need some new functionality in C, when that is added B does no longer run or build, so B has to be changed, and tested, test and delays cost the company 500000 USD - do you think management consider that no big deal ?
> Of course, there are situations where this is sinply wrong. If I must > anticipate the situation that my implementation might change, I definitely > am better off with properties. But for > 90% of all classes with data > members this is NOT the case. And if I make a mistake here, the cost is low > - mostly recompilation, and some syntax errors. Definitely not worth to > make everything private.... - at least until auto-properties were invented. Definitely worth doing.
It costs practically nothing. You declare the fields private and let the IDE generate the public property.
And can save you a ton of problems later.
And yes - it may only be a few percent of properties that will ever need functionality beyond default.
But the problem is that we do not know what those few percentages are when we write the code.
Code tend to be used much longer than original intended. 10-25 years are not unrealistic.
Nobody can guarantee that a given field will not need to be changed for so long a time span.
Arne
Marc Gravell - 04 Feb 2008 13:57 GMT > But for the very basic, is there any reason i should be using > properties instead of public variables? > In fact for the basic is there any difference in execution time > between get/set and direct access? Basically, it just isn't good design: * You can't change the internals (for instance, to use a facade) without breaking the clients * You can't change to properties without it being a breaking change (esp. if callers have used "ref") * You can't use validation or virtual * You can't data-bind to properties (without some work), and can't raise change notifications
Re performance - for a simple pass-thrue, the JIT should inline it, so nope.
You'll be glad to hear to C# 3 (in VS 2008) takes away the effort excuse for not using properties, via auto-implemented properties:
class SomeClass { public int Data {get;set;} }
there you go! A proper pass-thru property implementation that you can flesh-out later if you need.
Marc
Marc Gravell - 04 Feb 2008 14:20 GMT As a random thought... I wonder if (in fantasy future C# wishing land) there would be any scope for the auto-property setters to declare partial OnBeforeFooChanged and OnAfterFooChanged methods... maybe even an OnPropertyChanged for optional INotifyPropertyChanged support - but I guess that as soon as you open the door even a little bit, it gets *very* complicated.
Just my random wish-list item for the day (well, OK, my /second/ wish- list item for today)
Marc
Marc Gravell - 04 Feb 2008 13:58 GMT Oh, also, you can't use fields to implement interfaces - only properties, methods, etc
Marc
BlackWasp - 04 Feb 2008 21:52 GMT In addition to the other useful comments, I have recently been maintaining that used public variables. These have been changed to properties as they caused data-binding problems with the Infragistics WinGrid control. I would expect to experience similar issues elsewhere too.
 Signature BlackWasp www.blackwasp.co.uk
>I was always taught in C++ that using public variables was a bad idea, > which i could understand, so some generic get/set methods were usually [quoted text clipped - 31 lines] > In fact for the basic is there any difference in execution time > between get/set and direct access? Marc Gravell - 04 Feb 2008 22:47 GMT > These have been changed to properties as they > caused data-binding problems with the Infragistics WinGrid control. Yes; almost all UI-binding uses TypeDescriptor.GetProperties(), which only works (normally) with properties. I have seen a TypeDescriptionProvider implementation that elevates FieldInfo to PropertyDescriptor, but I wouldn't recommend it...
Marc
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|