Why is it "methods against properties"? A method does something. A property is, well, a member of an object. They're totally different things, although two kinds of methods commonly written - getters and setters - correspond to properties. Since comparing properties with methods in general is not meaningful, I'll assume you meant to talk about getters/setters.
Getter and setter method pairs are a code smell.
Not necessarily, I'd argue, but either way this isn't a matter of getters/setters vs. properties but a matter of whether either should be used. Also note that you can e.g. leave out the setX
part just like you can make read-only properties.
What is important to a consumer of an object is what it does, not how it does it. Its behavior is what it does; its state is how it does it. If you find yourself caring about an object's state (except for persistence, though this also breaks OO), you're simply not doing OOP and losing out on its advantages.
A highly questionable attitude. If the GUI wants to output data held by a DataStuffManagerImpl
, it needs to get that number from it somehow (and no, cramming half of the application into the widget class is not an option).
As the property gets more and more complex, the performance indication of using a property seems less and less truthful.
[Methods have] No performance guarantees. The API will remain truthful even if the method gets more complex. The consumer will need to profile their code if they are running in to performance issues, and not rely on word-of-API.
In almost all cases, all the validation logic etc. is still effectively O(1), or otherwise negible in cost. If not, perhaps you've gone too far and it's time for a change. And a getX()
method is usually treated as cheap as well!
Sure, typing myObject.Length is easier than typing myObject.Length(), but couldn't that be fixed with a little syntactic sugar?
Properties are that syntactic sugar.
Less for the consumer to think about. Does this property have a setter? A method sure doesn't.
"Is there a setter for this getter?" Same difference.
The programmer of the API will think more deeply about methods with return values, and avoid modifying the object's state in such methods, if possible. Separation of commands from queries should be enforced wherever possible.
I'm not sure what you're trying to tell us here. For properties, there's an even stronger unwritten law not to cause side effects.
If you're looking for dynamic runtime polymorphism, have you checked out the dynamic
keyword in C# 4.0? If it meets your need, I would imagine it's a lot simpler than what you're trying to do.
See Rob Conery's work with Massive, where he demonstrates how to build a dynamic ORM in C# 4.0 using 400 lines of code.
Creating proxy classes at runtime is not exactly an unprecedented technique, see Castle Dynamic Proxy and FasterFlect. If your only worry is that you're breaking some architectural austronaut's rule book, I'm not sure it's worth worrying about.
Best Answer
Stop!
You have a bigger problem than the readability. It looks like you don't understand how object initializers work.
Let's create a disposable class which traces its execution:
Now, let's write an app which initializes this class in three different ways (sorry, it's too big; I'll explain it more in details later):
There are three types of initialization here:
Before continuing to read the answer, ask yourself two questions:
Those techniques are totally different, and there is effectively two bugs: only one of them is correct.
1. Constructor
has nothing wrong, but it's the actual implementation of the constructor which is wrong. Constructors shouldn't throw exceptions, and one of the reasons is that it may cause inconsistent state when the object is used inside a
using
block: it's not fully initialized yet, so it will not be disposed, causing disaster if the unfinished initialization allocated some resources which should have been disposed.is basically the same as:
As you can see, there is no
try
around the constructor, so an exception within it would terminate the program before reachinga.Dispose()
: in all cases, we can't invoke a method of an object which is not initialized yet.The setter of
Hello
throws an exception; the constructor should have been using the backing field directly, instead of the property.2. Object initializer
is itself incorrect, and if you have used Code Analysis even at Minimum Recommended Rules level, you would have seen the warning CA2000, telling that:
What it that?!
That is the indicating that somewhere, an object is created and not disposed. To avoid concurrency issues, when you use an object initializer, a temporary instance of created:
is transformed by the compiler into:
Indeed, when you use an object initializer inside a
using (...)
:using
,using
block runs.Any exception thrown when assigning properties will prevent disposing the object, since the assignment happens before the
try/finally
.3. Late assignment
is correct. Since the constructor is not expected to throw an exception (and if it will, it would be the fault of the person who implemented the constructor, not the person who is using it within the
using
), all exceptions will occur within thetry
block, resulting in thedemo
object being properly disposed.Conclusion:
using
should contain either:A parameterless constructor,
A constructor which takes parameters,
given that constructors are not expected to throw exceptions.
using
should not contain an object initializer: properties should be initialized within theusing { ... }
, in order to guarantee the proper disposal of objects.Readability
Now that you've understood that the two pieces of code in your question are totally difference, since one is correct, and another one is buggy, let's talk readability.
Until C# 4.0, object initialization was slightly more readable than a similar constructor:
Here, I have no idea what is "1" or "16" or "1929". A person who is not at all familiar with hardware wouldn't know what "Intel® Xeon® E5-2620" is. No one would find what is
true
.Instead:
is much more readable.
.NET Framework introduced named arguments, and since then, a constructor can be as readable as an object initializer, while being more compact. For example, title is explicit enough, and we would consider that anyone will understand the names of processors, so we can write:
We have seen that with named arguments, a constructor can be as readable as an object initializer. What about performance?
Above, I've explained that an object initializer
this.a = new A { B = b }
is translated by the compiler into:If the only thing the constructor is doing is to assign fields or properties from arguments, then the performance would be approximately the same. Unless your office mate can give precise profiling results and benchmarks proving his point, his statement about the performance should be considered wrong.