I've always found the conservative approach to be best, when working in C# anyway. Because properties are syntactically the same as fields, they should work like fields: no exceptions, no validation, no funny business. (Indeed, most of my properties start out as simple fields, and don't become properties until absolutely necessary.) The idea is that if you see something that looks like it's getting or setting a field set, then it IS something like getting or setting a field, in terms of functionality (there is no exception thrown), overall efficiency (setting variables doesn't trigger a cascade of delegate calls, for example) and effect on program's state (setting a variable sets that variable, and doesn't call lots of delegates that could do just about anything).
Sensible things for a property set to do include setting a flag to indicate that there's been a change:
set {
if(this.value!=value) {
this.changed=true;
this.value=value;
}
}
Perhaps actually set a value on another object, e.g.:
set { this.otherObject.value=value; }
Maybe disentangle the input a bit, to simplify the class's internal code:
set {
this.isValid=(value&Flags.IsValid)!=0;
this.setting=value&Flags.SettingMask;
}
(Of course, in these latter two cases, the get function might well do the opposite.)
If anything more complicated needs to happen, in particular calling delegates, or performing validation, or throwing exceptions, then my view is that a function is better. (Quite often, my fields turn into properties with get and set, and then end up as a get property and a set function.) Similarly for the getters; if you're returning a reference to something, it's no problem, but if you're creating a whole new large object and filling it in each time the property is read -- not so hot.