Reputation: 897
I enjoy and highly recommend Juval Lowy's - C# Coding Standard. Juval explicitly avoids rationale for each directive in order to keep the standard tight (see the preface). However, there are a few directives for which I find myself curious as to the rationale.
What is the specific rationale to the following directives from Lowy's C# standard?
Hopefully there are hard (non-subjective) answers to these.
1.13 Avoid fully qualified type names. Use the "using" statement instead.
Is this a performance issue? Sometimes I only need one instance of the fully qualified name and adding a using seems heavy.
1.26 Use empty parenthesis on parameterless-anonymous methods. Omit the parenthesis only if the anonymous method could have been used on any delegate.
Actually I am just confused by the second sentence. Explanation with example(s) would help, thank you.
2.19 Avoid defining custom exception classes
What are the considerations in minimizing their numbers? (He next gives guidelines if you do define them (in 2.20).)
2.29 Avoid using the ternary conditional operator
Too hard for the reader to digest, or other considerations?
2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.
I don't think I do this, but I am curious...why not?
2.47 Avoid interfaces with one member.
Because it is always/usually more prefereable to do what? One method interfaces work when?
2.53 Prefer using explicit interface implementation
Why? Also, Jon Skeet disagrees here.
Thanks in advance! Robert
Upvotes: 23
Views: 5970
Reputation: 28112
A lot of these guidelines speak to the "quality attributes" of good software design (i.e. maintainability, reliability, reusability, testability, expandability, debugability, interoperability, and what other -ilities you can name).
Often people create code that works fine at the time but may not be the best choice when considering all the quality attributes (in the sense of "where can this software go in the future" or "someone else has to use this code, too").
For example:
2.29 Avoid using the ternary conditional operator
I have no problem with ternary expressions, per se, but by writing code such as: int result = CheckMethod() ? OnTrueDoThis() : OnFalseDoThat()... you are saying, "I have a conditional that, if true (or false), you can do one and only one thing." The whole construct discourages expandability. You have to recreate the construct (with an if..else statement).
Similarly...
2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.
You called a function and essentially "discarded" the results for later use. If that information is needed later, either the function would have to be called again or the structure of the code would have to be rewritten. It would also make checking or logging the results (for future debugging) more difficult.
Upvotes: 4
Reputation: 5216
2.29 Ternary operator
To start with, if you start to use the ternary operator, there should be a reason for the use of the ternary operator over a regular if-then-else. Observe :
if (x == 0) {...} else{...} //A set of statements demand a regular If-then-else
//A simple assignment can be handled by the ternary operator
y = (x == 0)? 1 : 0 //this is readable and how it should be used
(x==0)? callSomething() : callSomethingElse() //this is NOT how it should be used
The ternary statement is meant for returning one of two values depending upon the conditional it is evaluating. This is extremely handy when doing FP. For call statements that do not return a value, you should revert to if-then-else.
Upvotes: 0
Reputation: 5523
Regarding 1.13 (Avoid fully qualified type names. Use the "using" statement instead):
It may be a bit more than readability. If you have too many usings at the beginning of the file, you have a class that is coupled with classes from too many namespaces.
The class is screaming out for refactoring. Using usings instead of fully-qualified class names lets you identify such tightly-coupled classes more easily.
Upvotes: 4
Reputation: 1953
2.29 Avoid using the ternary conditional operator I have no problems with "simple" uses of the ternary operator but have recommended against using it in a nested fashion:
// This is fine
x := (conditionA) ? true_resultA : false_resultA;
// This would probably be clearer using if-then-elseif
x := (conditionA) ?
((conditionA1) ? true_resultA1 : (condition2) ? true_result2 : false_result2) :
((conditionA2) ? true_resultA2 : false_resultA2);
Upvotes: 11
Reputation: 1601
Obviously, I'm not Juval, but I can take a stab at these
1.13 Avoid fully qualified type names. Use the "using" statement instead.
Performance can't be the issue here. I'm sure the issue is readability.
1.26 Use empty parenthesis on parameterless-anonymous methods. Omit the parenthesis only if the anonymous method could have been used on any delegate.
public delegate void Foo1();
public delegate void Foo2(int val);
public void Foo()
{
Foo1 first = delegate { Console.WriteLine("Hello world"); };
Foo2 second = delegate { Console.WriteLine("Hello world"); };
Foo1 third = delegate() { Console.WriteLine("Hello world"); };
Foo2 fourth = delegate() { Console.WriteLine("Hello world"); }; // does not compile
}
Without the parens, the anonymous delegate can be applied to any delegate. With the parens, you're being specific about the signature of the delegate. Prefer the second syntax unless you really need the flexibility.
2.19 Avoid defining custom exception classes
Again, readability is the issue here. The framework exception classes are rich and well-understood. Be wary when replacing them.
2.29 Avoid using the ternary conditional operator
It's a readability and expandability thing. I don't really agree, but it's a standard religious fight.
2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.
Partially this is readability, and partially it's for ease of debugging. I've starting to assign almost everything to temporary variables just so that they're easily found in the debugger later on.
2.47 Avoid interfaces with one member.
"Avoid" is kinda like "prefer", he's just saying think twice before you do it. If you only have one member, is the interface really modeling something useful and complete in your design? It's pretty rare to have a class with just one member, think seriously about why your interface is any different.
2.53 Prefer using explicit interface implementation
This is similar to the idea of using the least-public accessor you can. If your class doesn't need to make the interface public, then it probably shouldn't. This is going to differ significantly based on your design, obviously, but given the fact that most people just make the interface implicit without really thinking about it, it's advice worth considering.
Upvotes: 9
Reputation: 31222
Here are some of my reactions of which I dare answer them :)
1.13 Avoid fully qualified type names. Use the "using" statement instead.
I disagree. It's certainly not performance related. It can lead to improved readability to have var foo = new Foo()
instead var foo = new MyCompany.MyNamespace.Helpers.Xml.Foo()
but other than that - no.
2.19 Avoid defining custom exception classes This is nonsense imho. You should avoid creating custom exceptions that derive from ApplicationException, but there is nothing wrong with custom exceptions (as long as you're not going to reinvent existing exceptions that is).
2.29 Avoid using the ternary conditional operator I have no idea why that would be a guideline. I have read that not all people use it and may not recognize it, but that is not a valid reason to not use a useful operator.
2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them. This is simply a readability issue in my opinion.
2.47 Avoid interfaces with one member. I also disagree here. You should avoid 'marker' interfaces though - interfaces with no marker, but who just serve the purpose that something is '...ble'. But, one method on an interface seems fine to me.
Upvotes: 2
Reputation: 1490
1.26 is about pre-lambda delegate { }
syntax.
// #1 Empty parenthesis on parameterless-anonymous methods would be:
delegate() { }
// #2 ... anonymous method could have been used on any delegate, is:
delegate { }
Remember, the latter can be assigned to any delegate, regardless of its parameters. The delegate just ignores these using some compiler trickery.
If you define a delegate taking no parameters, explicitly say so using #1. Don't "leave the parenthesis out because your delegate doesn't take any parameters anyway".
Upvotes: 5
Reputation: 25513
This is my best stab at the questions you've listed. For the ones that I can't really say, I've omitted.
1.13 Avoid fully qualified type names. Use the "using" statement instead.
Readability. It's must harder to read code when you have to read fully qualified type names.
2.19 Avoid defining custom exception classes
The .NET framework comes with a good set of exceptions built into the system. Unless the exception you're modeling is business domain specific, you'll probably be able to use one of the existing exception classes.
2.29 Avoid using the ternary conditional operator
I think this is most likely because he thinks people may not understand the operator, but I disagree.
2.47 Avoid interfaces with one member.
He might be warning people of building interfaces that are too thin. However, I would actual say the converse, warning people of making interfaces too verbose. If you've ever had to deal with ASP.NET MembershipProvider, you know what I'm talking about.
2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.
A couple of reasons I can think of here. Readability. It can make conditional statements hard to understand if you are making function calls in them. Also, it's harder to debug if you're not watching.
2.53 Prefer using explicit interface implementation
I believe his reasoning here is to for brevity. However, I don't actually agree with this assessment. I think Jon is correct, implicit interface should be used when you can, and explicit when appropriate.
Upvotes: 3