L\28i8ons
Coding Guidelines
for C# 3.0, 4.0 and 5.0
Dennis Doomen
Version 5.0.0
October 18, 20161. Introduction
1.1. What is this?
This document attempts to provide guidelines (or coding standards if you like) for coding in Ci 3.0, 4.0 or 5.0
that are both useful and pragmatic. Of course, if you create such a document you should practice what you
preach. So rest assured, these guidelines are representative to what we at Aviva Solutions do in our day-to-
day work. Notice that not all guidelines have a clear rationale. Some of them are simply choices we made at
Aviva Solutions. In the end, it doesn't matter what choice you made, as long as you make one and apply it
consistently,
Visual Studio's Static Code Analysis (which is also known as FxCop) and StyleCop can already automatically
enforce a lot of coding and design rules by analyzing the compiled assemblies. You can configure it to do that,
at compile time or as part of a continuous or daily build. The companion site
\www.esharpeodingguidelines.com provides a list of code analysis rules depending on the type of code base
you're dealing with. This document just provides an additional set of rules and recommendations that should
help you achieve a more maintainable code base.
1.2. Why would you use this document?
Although some might see coding guidelines as undesired overhead or something that limits creativity, this
approach has already proven its value for many years. This is because not every developer:
‘+ is aware that code is generally read 10 times more than itis changed;
‘+ is aware of the potential pitfalls of certain constructions in CH;
‘+ is up to speed on certain conventions when using the NET Framework such as 1bisposable or the
deferred execution nature of LING;
‘+ is aware of the impact of using (or neglecting to use) particular solutions on aspects like security,
performance, multi-language support, etc;
‘+ realizes that not every developer is as capable, skilled or experienced to understand elegant, but
potentially very abstract solutions;
1.3. Basic principles
‘There are many unexpected things | run into during my work as a consultant, each deserving at least one
guideline. Unfortunately, | still need to keep this document within a reasonable size. But unlike what some
junior developers believe, that doesn't mean that something is okay just because it is not mentioned in this.
document,
In general, if| have a discussion with a colleague about a smell that this document does not cover, I'll refer
back to a set of basic principles that apply to all situations, regardless of context. These include:
‘+ The Principle of Least Surprise (or Astonishment): you should choose a solution that everyone can
understand, and that keeps them on the right track.
‘+ Keep It Simple Stupid (a.k.a. KISS): the simplest solution is more than sufficient.
* You Ain't Gonna Need It (a.k.a. YAGNI): create a solution for the problem at hand, not for the ones you
think may happen later on. Can you predict the future?'* Don't Repeat Yourself (a.k.a. DRY): avoid duplication within a component, a source control repository or
a bounded context, without forgetting the Rule of Three heuristic.
‘© Ingeneral, generated code should not need to comply with coding guidelines. However, if itis possible to
modify the templates used for generation, try to make them generate code that complies as much as
possible.
Regardless of the elegance of someone's solution, if it's too complex for the ordinary developer, exposes
unusual behavior, or tries to solve many possible future issues, itis very likely the wrong solution and needs
redesign. The worst response a developer can give you to these principles is: "But it works?"
1.4. How do you get started?
‘+ Ask all developers to carefully read this document at least once. This will give them a sense of the kind of
guidelines the document contains.
‘+ Make sure there are always a few hard copies of the Quick Reference close at hand.
‘+ Include the most critical coding guidelines on your Project Checklist and verify the remainder as part of
your Peer Review.
© Consider forking the original sources on Githiub and create your own internal version of the document.
‘+ Decide which CA rules are applicable for your project and store these somewhere, such as your source
control system, or create a custom Visual Studio Rule Set. The companion site offers rule sets for both
line-of-business applications and more generic code bases, like frameworks and class libraries
‘+ Add a custom Code Analysis Dictionary containing your domain or company-specific terms, names and
concepts. If you don't, Static Analysis will report warnings for (parts of) phrases thet are not in its
internal dictionary.
‘+ Configure Visual Studio to verify the selected CA rules as part of the Release build. Then they won't
interfere with normal developing and debugging activities, but still can be run by switching to the
Release configuration.
‘+ Add an item to your project checklist to make sure all new code is verified against CA violations, or use
something like Check-in Policy or a Git commit hook to prevent any code from violating CA rules at all
+ ReSharper has an intelligent code inspection engine that, with some configuration, already supports
many aspects of the Coding Guidelines. it automatically highlights any code that does not match the
rules for naming members (e.g. Pascal or Camel casing), detects dead code, and many other things. One
click of the mouse button (or the corresponding keyboard shortcut) is usually enough to fix
‘+ ReSharper also has a File Structure window that displays an overview of the members of your class or
interface, and allows you to easily rearrange them using a simple drag-and-drop action.
‘© Using GhostDoc you can generate XML comments for any member using a keyboard shortcut. The
beauty of itis that it closely follows the MSDN-style of documentation. However, you have to be careful
ot to misuse this tool, and use it as a starter only.
1.5. Why did we create it?
‘The idea started in 2002 when Vic Hartog (Philips Medical Systems) and | were assigned the task of writing up
a coding standard for CH 1.0, Since then, I've regularly added, removed and changed rules based on
experiences, feedback from the community and new tooling support offered by a continuous stream of new
Visual Studio releases
Additionally, after reading Robert C. Martin's book Clean Code: A Handbook of Agile Software Craftsmanship,
became a big fan of his ideas and decided to include some of his smells and heuristics as guidelines. Notice‘though, that this document is in no way a replacement for his book. | sincerely recommend that you read his
book to gain a solid understanding of the rationale behind his recommendations.
I've also decided to include some design guidelines in addition to simple coding guidelines. They are too
important to ignore and have a big influence in reaching high quality code.
1.6. Is this a coding standard?
The document does not state that projects must comply with these guidelines, neither does it say which
{guidelines are more important than others. However, we encourage projects to decide themselves which
guidelines are important, what deviations a project will use, who is the consultant in case doubts arise, and
‘what kind of layout must be used for source code. Obviously, you should make these decisions before starting
the real coding work
Tohelp you in this decision, I've assigned a level of importance to each guideline:
Guidelines that you should never skip and should be applicable to all situations
© Strongly recommended guidelines
© May not be applicable in ll situations
1.7. Feedback and disclaimer
‘This document has been compiled using many contributions from community members, blog posts, on-line
discussions and many years of developing in CH. If you have questions, comments or suggestions, just let me
know by sending me an email at
[email protected], creating an issue or Pull Request on
GitHub, or ping me at http://twitter.com/ddoomen. | will try to revise and republish this document with new
insights, experiences and remarks on a regular basis.
Notice though that it merely reflects my view on proper C# code so Aviva Solutions will not be liable for any
direct or indirect damages caused by applying the guidelines of this document. This document is published
under a Creative Commons license, specifically the Creative Commons Attribution-ShareAlike 4.0 license.2. Class Design Guidelines
‘A class or interface should have a single purpose (AV1000) ©
Aclass or interface should have a single purpose within the system it functions in. In general, a class either
represents a primitive type like an email or ISBN number, an abstraction of some business concept, a plain
data structure, or is responsible for orchestrating the interaction between other classes. It is never a
combination of those. This rule is widely known as the Single Responsibility Principle, one of the S.0.L1.0,
Principles.
Tip: A class with the word and in itis an obvious violation of this rule.
Ise Design Patterns to communicate the intent of a class. If you can't assign a single design pattern to a
class, chances are that it is doing more than one thing,
Note If you create a class representing a primitive type you can greatly simplify its use by making it
immutable.
Only create a constructor that returns a useful object (AV1001) ©
‘There should be no need to set additional properties before the object can be used for whatever purpose it
was designed. However, if your constructor needs more than three parameters (which violates AV1561), your
class might have too much responsibility (and violates AV1000).
An interface should be small and focused (AV1003) @
Interfaces should have a name that cleariy explains their purpose or role in the system. Do not combine many
vaguely related members on the same interface just because they were all on the same class. Separate the
members based on the responsibility of those members, so that callers only need to call or implement the
Interface related to a particular task. This rule is more commonly known as the Interface Segregation
Principle,
Use an interface rather than a base class to support multiple implementations
(Av1004) ©
If you want to expose an extension point from your class, expose it as an interface rather than as a base class.
You don't want to force users of that extension point to derive their implementations from a base class that
might have an undesired behavior. However, for their convenience you may implement a(n abstract) default
implementation that can serve as a starting point.
Use an interface to decouple classes from each other (AV1005) ©
Interfaces are a very effective mechanism for decoupling classes from each other:
‘+ They can prevent bidirectional associations;
‘+ They simplify the replacement of one implementation with another;
‘+ They allow the replacement of an expensive external service or resource with a temporary stub for use
in a non-production environment,
+ They allow the replacement of the actual implementation with a dummy implementation or a fake
object in a unit test;'* Using a dependency injection framework you can centralize the choice of which class is used whenever a
specific interface is requested.
Avoid static classes (AV1008) ©
With the exception of extension method containers, static classes very often lead to badly designed code.
They are also very difficult, if not impossible, to test in isolation, unless you're willing to use some very hacky
tools.
Note
‘you really need that static class, mark it as static so that the compiler can prevent instance members
and instantiating your class. This relieves you of creating an explicit private constructor.
Don't hide inherited members with the new keyword (AV1010) @
Not only does the new keyword break Polymorphism, one of the most essential object-orientation principles,
it also makes sub-classes more difficult to understand. Consider the following two classes:
public class Book
{
public virtual void Print()
«
Console.writeLine( "Printing Book");
x
>
public class PocketBook : Book
{
public new void Print()
«
Console.writeLine( "Printing Pocket8ook");
x
y
This will cause behavior that you would not normally expect from class hierarchies:
PocketBook pocketBook
new PocketBook();
pocketBook.Print(); // Outputs
rinting PocketBook *
((Book)pocketBook) .Print(); // Outputs “Printing Book
It should not make a difference whether you call Print() through a reference to the base class or through the
derived class.
It should be possible to treat a derived object as if it were a base class object (AV1011)
e
In other words, you should be able to use a reference to an object of a derived class wherever a reference to
its base class object is used without knowing the specific derived class. A very notorious example of a
violation of this rule is throwing a Not Implementedexception when overriding some of the base-class
methods. A less subtle example is not honoring the behavior expected by the base clas.
Note: This rule is also known as the Liskov Substitution Principle, one of the 5.0.1.0. principles.Don't refer to derived classes from the base class (AV1013) @
Having dependencies from a base class to its sub-classes goes against proper object-oriented design and
might prevent other developers from adding new derived classes.
Avoid exposing the other objects an object depends on (AV1014)@
If you find yourself writing code lke this then you might be violating the Law of Demeter
someObject .SomeProperty .GetChild().Foo()
‘An object should not expose any other classes it depends on because callers may misuse that exposed
property or method to access the object behind it. By doing so, you allow calling code to become coupled to
the class you are using, and thereby limiting the chance that you can easily replace it in a future stage.
Note
sing a class that is designed using the Fluent Interface pattern seems to violate this rule, but it is
simply returning itself so that method chaining is allowed.
Exception: Inversion of Control or Dependency Injection frameworks often require you to expose a
dependency as a public property. As long as this property is not used for anything other than dependency
injection | would not consider it a violation
Avoid bidirectional dependencies (AV1020) @
This means that two classes know about each other's public members or rely on each other's internal
behavior. Refactoring or replacing one of those classes requires changes on both parties and may involve a lot
of unexpected work. The most obvious way of breaking that dependency is to introduce an interface for one
of the classes and using Dependency Injection.
Exception: Domain models such as defined in Domain-Driven Design tend to occasionally involve bidirectional
associations that model real-life associations. In those cases, make sure they are really necessary, and if they
are, keep them in.
Classes should have state and behavior (AV1025) ©
In general, if you find a lot of data-only classes in your code base, you probably also have a few (static) classes
with a lot of behavior (see AV1008). Use the principles of object-orientation explained in this section and
move the logic close to the data it applies to
Exception: The only exceptions to this rule are classes that are used to transfer data over a communication
channel, also called Data Transfer Objects, or a class that wraps several parameters of a method,3. Member Design Guidelines
Allow properties to be set in any order (AV1100) ©
Properties should be stateless with respect to other properties, i.e. there should not be a difference between
first setting property DataSource and then oatamenber or vice-versa,
Use a method instead of a property (AV1105) ©
If the work is more expensive than setting a field value.
If it represents a conversion such as the Object. Tostring method.
Ifitreturns a different result each time itis called, even if the arguments didn't change. For example, the
NewGuid method returns a different value each time itis called
If the operation causes a side effect such as changing some internal state not directly related to the
property (which violates the Command Query Separation principle}.
Exception: Populating an internal cache or implementing |azy-loacing is a good exception.
Don't use mutual exclusive properties (AV1110) ©
Having properties that cannot be used at the same time typically signals a type that represents two conflicting
concepts. Even though those concepts may share some of their behavior and states, they obviously have
different rules that do not cooperate.
This violation is often seen in domain models and introduces all kinds of conditional logic related to those
conflicting rules, causing a ripple effect that significantly increases the maintenance burden.
Amethod or property should do only one thing (AV1115) @
Similarly to rule AV1000, a method should have a single responsibility.
Don't expose stateful objects through static members (AV1125) @
A stateful object is an object that contains many properties and lots of behavior behind it. If you expose such
an object through a static property or method of some other object, it will be very difficult to refactor or unit
test a class that relies on such a stateful object. In general, introducing a construction like that is a great
example of violating many of the guidelines of this chapter.
Aclassic example of this is the HttpContext .current property, part of ASP.NET. Many see the Httpcontext
class as a source of a lot of ugly code. In fact, the testing guideline solate the Ugly Stuff often refers to this
Return an IEnumerable
or ICollection instead of a concrete collection
class (AV1130) @
‘You generally don't want callers to be able to change an internal collection, so don't return arrays, lists or
other collection classes directly. Instead, return an LEnumerable, or, if the caller must be able to determine
the count, an rcollectioncT>.Note: If you're using .NET 4.5, you can also use TReadOnlyCollection, IReadOnlyti
IReadonlybictionary.
Properties, methods and arguments representing strings or collections should never be
null (AV1135) @
Returning null can be unexpected by the caller. Always return an empty collection or an empty string instead
of @ null reference. This also prevents cluttering your code base with additional checks for nul, or even
worse, string. TsNullorenpty()
Define parameters as specific as possible (AV1137)@
If your member needs a specific piece of data, define parameters as specific as that and don't take a container
object instead. For instance, consider a method that needs a connection string that is exposed through a
central 1Configuration interface. Rather than taking a dependency on the entire configuration, just define a
parameter for the connection string. This not only prevents unnecessary coupling, it also improved
maintainability in the long run
Note: An easy trick to remember this guideline is the Don't ship the truck if you only need a package.
Consider using domain-specific value types rather than primitives (AV1140) ©
Instead of using strings, integers and decimals for representing domain-specific types such as an ISBN
number, an email address or amount of money, consider creating dedicated value objects that wrap both the
data and the validation rules that apply to it. By doing this, you prevent ending up having multiple
implementations of the same business rules, which both improves maintainability and prevents bugs.4. Miscellaneous Design Guidelines
Throw exceptions rather than returning some kind of status value (AV1200) @
‘Acode base that uses return values to report success or failure tends to have nested if-statements sprinkled
all over the code. Quite often, a caller forgets to check the return value anyway. Structured exception
handling has been introduced to allow you to throw exceptions and catch or replace them at a higher layer. In
‘most systems it is quite common to throw exceptions whenever an unexpected situation occurs.
Provide a rich and meaningful exception message text (AV1202) ©
‘The message should explain the cause of the exception, and clearly describe what needs to be done to avoid
the exception,
Throw the most specific exception that is appropriate (AV1205) ©
For example, if a method receives a null argument, it should throw ArgurentNullException instead of its
base type Argunentexception
Don't swallow errors by catching generic exceptions (AV1210) @
‘Avoid swallowing errors by catching non-specific exceptions, such as Exception, Systenéxception, and so on,
in application code. Only top-level code, such as a last-chance exception handler, should catch a non-specific
exception for logging purposes and a graceful shutdown of the application.
Properly handle exceptions in asynchronous code (AV1215) @
When throwing or handling exceptions in code that uses async/await or a Task remember the following two
rules:
‘+ Exceptions that occur within an asyne/await block and inside a Task's action are propagated to the
awaiter,
‘+ Exceptions that occur in the code preceding the asynchronous block are propagated to the caller.
Always check an event handler delegate for nu11 (AV1220) ®
‘An event that has no subscribers is nul1, so before invoking, always make sure that the delegate list
represented by the event variable Is not null. Furthermore, to prevent conflicting changes from concurrent
threads, use a temporary variable to prevent concurrent changes to the delegate.
event EventHandler Notify;
void RaiseNotifyEvent(Notifyeventargs args)
€
Event#andler handlers = Notify;
if (handlers != null)
«
handlers(this, args);fou can prevent the delegate list from being empty altogether. Simply assign an empty delegate like this:
event EventHandler Notify = delegate {};
Use a protected virtual method to raise each event (AV1225) @
Complying with this guideline allows derived classes to handle a base class event by overriding the protected
method. The name of the protected virtual method should be the same as the event name prefixed with On
For example, the protected virtual method for an event named Tinechanged is named OnTimechanged
Note:
jerived classes that override the protected virtual method are not required to call the base class
implementation, The base class must continue to work correctly even if its implementation is not called,
Consider providing property-changed events (AV1230) ©
Consider providing events that are raised when certain properties are changed. Such an event should be
named PropertyChanged, where Property should be replaced with the name of the property with which this
event is associated
Nott
If your class has many properties that require corresponding events, consider Implementing the
{Not fyPropertyChanged interface instead. Itis often used in the Presentation Model and Model-View-
ViewlViodel patterns.
Don't pass nul] as the sender argument when raising an event (AV1235)
Often an event handler is used to handle similar events from multiple senders. The sender argument is then
Used to get to the source of the event. Always pass a reference to the source (typically this) when raising the
event. Furthermore don't pass null as the event data parameter when raising an event. If there is no event
data, pass EventArgs. empty instead of null
Exception: On static events, the sender argument should be null
Use generic constraints if applicable (AV1240) @
Instead of casting to and from the object type in generic types or methods, use where constraints or the as
operator to specify the exact characteristics of the generic parameter, For example:
class SoneClass
0
11 Don't
class MyClass
{
void SoneMethod(T t)
«
object temp
SoneClass obj = (SoneClass) tenp;
11 bo
class MyClass where T : SoneClass
{
void SoneMethod(T t)SoneClass obj
Evaluate the result of a LINQ expression before returning it (AV1250) @
Consider the following code snippet
public
{
wunerable GetGoldMenbercustoners()
const decimal GoldMenberthresholdinguro = 1000000;
var query
from customer in db.Customers
where customer.Salance > GoldMerberThresholdinEuro
select new GoldMenber(customer.Name, customer.8alance);
return query;
Since LINQ queries use deferred execution, returning query will actually return the expression tree
representing the above query. Each time the caller evaluates this result using a foreach cycle or similar, the
entire query is re-executed resulting in new instances of GoldMenber every time. Consequently, you cannot
use the == operator to compare multiple GoldMenber instances. Instead, always explicitly evaluate the result
of a LING query using ToList(), ToArray() or similar methods.5. Maintainability Guidelines
Methods should not exceed 7 statements (AV1500) @
‘A method that requires more than 7 statements is simply doing too much or has too many responsibilities. It
also requires the human mind to analyze the exact statements to understand what the code is doing, Break it
down into multiple small and focused methods with self-explaining names, but make sure the high-level
algorithm is still clear.
Make all members private and types internal by default (AV1501) @
To make a more conscious decision on which members to make available to other classes, first restrict the
scope as much as possible. Then carefully decide what to expose as a public member or type.
Avoid conditions with double negatives (AV1502) @
Although a property like custoner.HasNoOrders makes sense, avoid using it in a negative condition like this
bool hasOrders = !customer.HasNoOrders;
Double negatives are more difficult to grasp than simple expressions, and people tend to read over the
double negative easily.
Name assemblies after their contained namespace (AV1505) ©
All DLLs should be named according to the pattern Company.Component.dll where Company refers to your
‘company's name and Component contains one or more dot-separated clauses. For example
AvivaSolutions.Web.Controls.dll.
‘As an example, consider a group of classes organized under the namespace AvivaSolutions..Web Binding
exposed by a certain assembly. According to this guideline, that assembly should be called
AvivaSolutions.heb.Binding.d1l.
Exception: If you decide to combine classes from multiple unrelated namespaces into one assembly, consider
suffixing the assembly name with Core, but do not use that suffix in the namespaces. For instance,
AvivaSolutions .Consulting.Core.dil.
Name a source file to the type it contains (AV1506) @
Use Pascal casing to name the file and don't use underscores.
Limit the contents of a source code file to one type (AV1507) ©
Exception: Nested types should, for obvious reasons, be part of the same file.
Name a source file to the logical function of the partial type (AV1508) ©
‘When using partial types and allocating a part per file, name each file ater the logical part that part plays. For
example:11 In WyClass.cs
public partial class MyClass
een
// In MyClass.Designer.cs
public partial class MyClass
Got
Use using statements instead of fully qualified type names (AV1510) ©
Limit usage of fully qualified type names to prevent name clashing. For example, don't do this:
var List = new systen.Collections.Generic.List()3
Instead, do this:
using Systen.Collections.Generic;
var List = new List()s
HFyou do need to prevent name clashing, use a using directive to assign an alias:
using Label = Systen.Web.UT-WebControls. Label;
Don't use "magic" numbers (AV1515) ®
Don't use literal values, either numeric or strings, in your code, other than to define symbolic constants. For
example:
public class whatever
{
public static readonly Color PapayaWhip = new Color(@xFFEFDS);
public const int MaxNumberofWheels = 183
Strings intended for logging or tracing are exempt from this rule. Literals are allowed when their meaning is
clear from the context, and not subject to future changes, For example:
mean = (a +b) / 23// okay
WaitMilliseconds(waitTimeInSeconds * 1980); // clear enough
If the value of one constant depends on the value of another, attempt to make this explicit in the code.
public class SoneSpecialContainer
{
public const int Maxrtens = 323
public const int HighWlaterMark = 3 * MaxTtems / 4; // at 75%
y
Note: An enumeration can often be used for certain types of symbolic constants,
Only use var when the type is very obvious (AV1520) ©‘Only use var as the result of a LINQ query, or if the type is very obvious from the same statement and using it
would improve readability. So don't
var i= 35 J/ what type? int? uint? Float?
var myfoo = MyFactoryMethod.Create("arg"); // Not obvious what base-class or
// interface to expect. Also difficult
// to refactor if you can't search for
J/ the class
Instead, use var like this:
var q = from order in orders where order.Ttens > 10 and order.TotalValue > 1000;
var repository = new RepositoryFactory.Get();
var list = new ReadOnlyCollection();
In all of three above examples itis clear what type to expect. For a more detailed rationale about the
advantages and disadvantages of using var, read Eric Lippert's Uses and misuses of implicit typing.
Declare and initialize variables as late as possible (AV1521) @
‘Avoid the C and Visual Basic styles where all variables have to be defined at the beginning of a block, but
rather define and initialize each variable at the point where it is needed.
Assign each variable in a separate statement (AV1522) @
Don't use confusing constructs like the one below:
var result = someField = GetSoneMethod();
Favor Object and Collection Initializers over separate statements (AV1523) ©
Instead of:
var startInfo = new ProcessStartInfo(“myapp.exe");
startInfo.Standardoutput = Console.Output;
startInfo.UseShellexecute = trues
Use Object Initializers:
var startInfo = new ProcessStartInfo("nyapp.exe")
«
Standardoutput = Console.Output,
Useshellexecute = true
h
Similarly, instead
var countrie:
countries .Add(
countries.Add("United States");
new List();
jetherlands
Use collection or dictionary initializers:
var countrie:
new List { "Netherlands", “United States" };Don't make explicit comparisons to true or false (AV1525)@
It is usually bad style to compare a bool-type expression to true or false. For example:
while (condition == false)// wrong; bad style
While (condition != true)// also wrong
while (((condition == true) == true)
while (condition)// 0k
rue)// where do you stop?
Don't change a loop variable inside a for loop (AV1530) ©
Updating the loop variable within the loop body is generally considered confusing, even more so if the loop
variable is modified in more than one place.
for (int index = 5 index < 10; ++index)
{
Af (_some condition_)
«
index = 11; // Wrong! Use "bresk' or ‘continue’ instead.
x
y
Avoid nested loops (AV1532) @
‘Amethod that nests loops is more difficult to understand than one with only a single loop. In fact, in most
cases nested loops can be replaced with a much simpler LINQ query that uses the from keyword twice or
more to join the data.
Always add a block after keywords such as if, else, while, for, foreach and case
(av1535)@
Please note that this also avoids possible confusion in statements of the form
if (b1) if (b2) Foo(); else Bar(); // which "if" goes with the ‘else’?
11 The right way:
if (bt)
«
Af (b2)
«
Foot);
}
else
«
Bar();
Always add a default block after the last case in a switch statement (AV1536) @
‘Add a descriptive comment if the default block is supposed to be empty. Moreover, if that block is not
supposed to be reached throw an Invalidoperationéxception to detect future changes that may fall through
the existing cases. This ensures better code, because all paths the code can travel have been thought about.void Foo(steing answer)
«
switch (answer)
«
‘
Console.WriteLine(“You answered with No”);
break;
case "yes":
{
Console.WriteLine("You answered with Yes");
break;
default:
{
// Not supposed to end up here.
‘throw new InvalidoperationException( "Unexpected answer " + answer);
}
Finish every if-else-if statement with an else-part (AV1537) @
For example:
void Foo(string answer)
«
Af (answer == no")
«
Console.WriteLine("You answered with No");
y
else if (answer
«
Console.WriteLine("You answered with Yes");
y
else
«
11 What should happen when this point is reached? Ignored? If not,
J/ throw an InvalidoperationException.
y
>
Be reluctant with multiple return statements (AV1540) @
One entry, one exit is a sound principle and keeps control flow readable. However, if the method is very small
and complies with guideline AV1500 then multiple return statements may actually improve readability over
some central boolean flag that is updated at various points.
Don't use if-else statements instead of a simple (conditional) assignment (AV1545) ©
Express your intentions directly. For example, rather than:bool pos;
if (val > @)
{
pos = true;
?
else
{
pos = false;
>
write
bool pos = (val > @);// initialization
Or instead of:
string result;
if (sonestring != null)
{
result = sonestrings
>
else
{
result = "Unavailable";
>
return result;
write:
return soneString ?? “unavailable’
Encapsulate complex expressions in a method or property (AV1547) @
Consider the following example:
Af (menber.HidesBaseClassMenber && (menber.NodeType = NodeType. Instancernitializer))
€
11 do sonething
In order to understand what this expression is about, you need to analyze its exact details and all of its
possible outcomes. Obviously, you can add an explanatory comment on top of it, but it is much better to
replace this complex expression with a clearly named method:
Lf (NonConstructorMenberUsesNewKeyword(menber))
t
11 do sonething
private bool NonConstructorMenberUsesNewkeyworé(Menber menber)
{return
(menber HidesBaseClassMenber &&
(menber NodeType != NodeType. Instancelnitializer)
You still need to understand the expression if you are modifying it, but the calling code is now much easier to
grasp.
Call the more overloaded method from other overloads (AV1551) @
This guideline only applies to overloads that are intended to provide optional arguments. Consider, for
example, the following code snippet:
public class Mystring
{
private string sonetext;
public int Indexof(string phrase)
«
return IndexoF(phrase, @);
y
public int IndexOF(string phrase, int startIndex)
«
return IndexOF(phrase, startIndex, someText-Length - startIndex);
}
public virtual int Indexof(string phrase, int startIndex, int count)
«
return soneText.IndexOf (phrase, startIndex, count);
y
>
‘The class MyString provides three overloads for the Indexof method, but two of them simply call the one
with one more parameter. Notice that the same rule applies to class constructors; implement the most
complete overload and call that one from the other overloads using the this() operator. Also notice that the
parameters with the same name should appear in the same position in all overloads.
Important: If you also want to allow derived classes to override these methods, define the most complete
overload as a protected virtual method that is called by all overloads.
Only use optional arguments to replace overloads (AV1553) ©
‘The only valid reason for using C#4.0's optional arguments is to replace the example from rule AV1551 with a
single method like:
public virtual int IndexoF(string phrase, int startInde
{
@, int count
return soneText.IndexOf(phrase, startindex, count);
If the optional parameter is a reference type then it can only have a default value of null. But since strings,
lists and collections should never be nu11 according to rule AV1235, you must use overloaded methods
instead.Note
he default values of the optional parameters are stored at the caller side. As such, changing the
default value without recompiling the calling code will not apply the new default value properly.
Note
hen an interface method defines an optional parameter, its default value is not considered during
overload resolution unless you call the concrete class through the interface reference. See this post by Eric
Lippert for more details.
Avoid using named arguments (AV1555) @
Ci 4.0's named arguments have been introduced to make it easier to call COM components that are known
for offering many optional parameters. If you need named arguments to improve the readability of the call to
‘a method, that method is probably doing too much and should be refactored.
Exception: The only exception where named arguments improve readability is when calling a method of some
code base you don't control that has a bool parameter, like this:
object] myAttributes = type.GetCustonattributes(typeof(MyAttribute), inherit: false);
Don't allow methods and constructors with more than three parameters (AV1561) ®
If you create a method with more than three parameters, use a structure or class to pass multiple arguments,
as explained in the Specification design pattern. In general, the fewer the parameters, the easier itis to
understand the method, Additionally, unit testing a method with many parameters requires many scenarios
to test.
Don't use ref or out parameters (AV1562) O
They make code less understandable and might cause people to introduce bugs. Instead, return compound
objects.
Avoid methods that take a bool flag (AV1564) @
Consider the following method signature:
public Custorer CreateCustomer(bool platinuatevel) {}
On first sight this signature seems perfectly fine, but when calling this method you will lose this purpose
completely:
Customer custoner = CreateCustoner(true);
Often, a method taking such a flag is doing more than one thing and needs to be refactored into two or more
methods. An alternative solution is to replace the flag with an enumeration.
Don't use parameters as temporary variables (AV1568) ©
Never use a parameter as a convenient variable for storing temporary state. Even though the type of your
temporary variable may be the same, the name usually does not reflect the purpose of the temporary
variable.
Always check the result of an as operation (AV1570) @If you use as to obtain a certain interface reference from an object, always ensure that this operation does
not return null. Failure to do so may cause a NulIReferenceException at a much later stage if the object did
not implement that interface.
Don't comment out code (AV1575) @
Never check in code that is commented out. Instead, use a work item tracking system to keep track of some
work to be done. Nobody knows what to do when they encounter a block of commented-out code. Was it
‘temporarily disabled for testing purposes? Was it copied as an example? Should | delete it?Language element Casing Example
6. Naming Guidelines
Use US-English (AV1701) ©
All type members, parameters and variables should be named using words from the American English
language,
* Choose easily readable, preferably grammatically correct names. For example, HorizontalALignnent is
more readable than AlignaentHorizontal.
‘Favor readability over brevity. The property name CanScroliHorizontally is better than Scrollabiex (an
obscure reference to the X-axis).
‘+ Avoid using names that conflict with keywords of widely used programming languages.
Exception: In most projects, you will use words and phrases from your domain and names specific to your,
company. Visual Studio's Static Code Analysis performs a spelling check on all code, so you may need to add
those terms to a Custom Code Analysis Dictionary,
Use proper casing for language elements (AV1702) ©
Language element Casing Example
Class, Struct Pascal AppDonain
Interface Pascal TBusinessService
Enumeration type Pascal Errortevel
Enumeration values Pascal Fatalérror
Event Pascal click
Private field Camel Lstrten
Protected field Pascal MainPanel
Constant field Pascal Maxinunttens
Constant Local variable Camel naxinunTtens
Read-only staticfield Pascal Redvalue
Local Variable Camel Listofvalues
Method Pascal Tostring
Namespace Pascal systen.orawing
Parameter Camel typeNane
Type Parameter Pascal Wwiew
Property Pascal BackColorDon't include numbers in variables, parameters and type members (AV1704) ©
In most cases they are a lazy excuse for not defining a clear and intention-revealing name.
Don't prefix fields (AV1705) @
For example, don't use g_or s_ to distinguish static from non-static fields. A method in which itis difficult to
distinguish local variables from member fields is generally too big. Examples of incorrect identifier names are:
_currentUser, mUserNane, m_loginTine
Don't use abbreviations (AV1706) ©
For example, use onsuttonClick rather than OnBtnClick. Avoid single character variable names, such as 4 or
9. Use index or query instead.
Exceptions: Use well-known abbreviations that are widely accepted or well-known in your work domain. For
instance, use UT instead of UserInterface.
Name a member, parameter or variable according to its meaning and not its type
(AV1707)@
‘+ Use functional names. For example, GetLength is a better name than Getint.
© Don't use terms lik
un, Class or Struct in a name.
‘© Identifiers that refer to a collection type should have plural names.
Name types using nouns, noun phrases or adjective phrases (AV1708) @
Bad examples include Searchexanination (a page to search for examinations), Conon (does not end with a
oun, and does not explain its purpose) and siteSecurity (although the name is technically okay, it does not
say anything about its purpose). Good examples include BusinessBinder, SnartTextBox, or
Editablesinglecustoner
Don't include terms like Utility or Helper in classes, Classes with names like that are usually static classes
and are introduced without considering object-oriented principles (see also AV1008)
Name generic type parameters with descriptive names (AV1709) @
'* Always prefix type parameter names with the letter T.
‘+ Always use a descriptive name unless a single-letter name is completely self-explanatory and a longer
name would not add value. Use the single letter T as the type parameter in that case.
'* Consider indicating constraints placed on a type parameter in the name of the parameter. For example, @
parameter constrained to ISession may be called TSession.
Don't repeat the name of a class or enumeration in its members (AV1710) @
class Employee
t
11 Wrong!
static GetEmployee() {}
Deleteemployee() (}
I) Rightstatic Get() {...}
Delete() {...}
// Wiso correct.
Addven30b() (...)
RegisterFormeeting() {...)
Name members similarly to members of related .NET Framework classes (AV1711) ©
NET developers are already accustomed to the naming patterns the framework uses, so following this same
pattern helps them find their way in your classes as well. For instance, if you define a class that behaves ike a
collection, provide members like Add, Renove and Count instead of AddTten, Delete or NunberOFTtens
Avoid short names or names that can be mistaken for other names (AV1712) @
Although technically correct, statements like the following can be confusing:
bool 601 = (lo == 18) ? (I1 == 11) : (101 != 101);
Properly name properties (AV1715) @
‘+ Name properties with nouns, noun phrases, or occasionally adjective phrases.
‘+ Name boolean properties with an affirmative phrase. E.g, CanSeek instead of CantSeek.
+ Consider prefixing boolean properties with 1s, Has, Can, Allows, or Supports.
* Consider giving a property the same name as its type. When you have a property that is strongly typed
to an enumeration, the name of the property can be the same as the name of the enumeration. For
‘example, if you have an enumeration named CacheLevel, a property that returns one of its values can
also be named CacheLevel.
Name methods using a verb or a verb-object pair (AV1720) @
Name methods using a verb like Show or a verb-object pair such as Showbialog. A good name should give a
hint on the what of a member, and if possible, the why.
Also, don't include And in the name of a method. It implies that the method is doing more than one thing,
which violates the single responsibility principle explained in AV1115,
Name namespaces using names, layers, verbs and features (AV1725) ©
For instance, the following namespaces are good examples of that guideline.
AvivaSolutions Commerce. Web
NHibernate. Extensibility
Microsoft ServiceModel .WebApL
Microsoft. VisualStudio. Debugging
Fluentassertion. Primitives
caliburnticro. Extensions
Note: Never allow namespaces to contain the name of a type, but a noun in its plural form (e.g. Collections)
is usually OK.
Use a verb or verb phrase to name an event (AV1735) @Name events with a verb or a verb phrase. For example: Click, Deleted, Closing, Minimizing, and Arriving.
For example, the declaration of the Search event may look like this:
public event EventHandler Search;
Use - ing and -ed to express pre-events and post-events (AV1737) ©
For example, a close event that is raised before a window is closed would be called Closing, and one that is
raised after the window is closed would be called Closed. Don't use Before or After prefixes or suffixes to
indicate pre and post events.
Suppose you want to define events related to the deletion of an object. Avoid defining the Deleting and
Deleted events as BeginDelete and Endbelete. Define those events as follows:
+ beleting: Occurs just before the object is getting deleted
+ Delete: Occurs when the object needs to be deleted by the event handler.
© Deleted: Occurs when the object is already deleted.
Prefix an event handler with On (AV1738) ©
Itis good practice to prefix the method that handles an event with on. For example, a method that handles
the Closing event can be named onClosing
Use an underscore for irrelevant lambda parameters (AV1739) ©
If you use a lambda statement, for instance, to subscribe to an event, and the actual parameters of the event
are irrelevant, use the following convention to make that more explicit
button.Click +=
>) => Handleclick();
Group extension methods in a class suffixed with Extensions (AV1745) ©
If the name of an extension method conflicts with another member or extension method, you must prefix the
call with the class name. Having them in a dedicated class with the Extensions suffix improves readability.
Post-fix asynchronous methods with Async or TaskAsync (AV1755) @
‘The general convention for methods that return Task or Task is to post-fix them with Async, but if
such a method already exists, use TaskAsync instead.7. Performance Guidelines
Consider using Any() to determine whether an IEnumerable is empty (AV1800)
6
When a method or other member returns an IEnumerable or other collection class that does not expose a
Count property, use the Any() extension method rather than Count() to determine whether the collection
contains items. If you do use Count(), you risk that iterating over the entire collection might have a significant
impact (such as when it really is an 1QueryablecT> to a persistent store).
Note: If you return an TenunerablecT> to prevent editing from outside the owner as explained in AV1130, and
you're developing in .NET 4.5 or higher, consider the new read-only classes.
Only use async for low-intensive long-running activities (AV1820) ©
The usage of async won't automagically run something on a worker thread like Task. Run does, It ust adds the
necessary logic to allow releasing the current thread, and marshal the result back on that same thread if a
long-running asynchronous operation has completed. In other words, use asyne only for /O bound
operations.
Prefer Task. Run for CPU-intensive activities (AV1825) ©
If you do need to execute a CPU bound operation, use Task.Run to offload the work to a thread from the
Thread Pool. Remember that you have to marshal the result back to your main thread manually
Beware of mixing up await/async with Task.Wait (AV1830)0
‘await does not block the current thread but simply instructs the compiler to generate a state-machine.
However, Task.wait blocks the thread and may even cause deadlocks (see AV1835).
Beware of async/await deadlocks in single-threaded environments (AV1835) ©
Consider the following asynchronous method:
private async Task Getdataasync()
«
var result = await MysdebService.GetDataasync();
return result. Tostring();
Now when an ASP.NET MVC controller action does this:
public ActionResult ActionAsyne()
{
var data = GetDataAsync().Result;
return View(data);
You end up with a deadlock. Why? Because the Result property getter will block until the async operation
has completed, but since an asyne method will automatically marshal the result back to the original threadand ASP.NET uses a single-threaded synchronization context, they'll be waiting on each other. A similar
problem can also happen on WPF, Silverlight or a Windows Store C#/XAML app. Read more about this here.8. Framework Guidelines
Use C# type aliases instead of the types from the System namespace (AV2201) @
For instance, use ob ject instead of object, string instead of string, and int instead of rnt32. These aliases
have been introduced to make the primitive types first class citizens of the C# language, so use them
accordingly.
Exception: When referring to static members of those types, it is custom to use the full CLS name, e.g
Int32.Parse() instead of int.Parse(). The same applies to members that need to specify the type they
return, e.g. Readint32, Geturnt6.
Properly name properties, variables or fields referring to localized resources (AV2205)
3)
‘The guidelines in this topic apply to localizable resources such as error messages and menu text.
‘+ Use Pascal casing in resource keys.
‘* Provide descriptive identifiers rather than short ones. Keep them concise where possible, but don't
sacrifice readability.
‘© Use only alphanumeric characters in naming resources.
Don't hard-code strings that change based on the deployment (AV2207) ©
Examples include connection strings, server addresses, etc. Use Resources, the Connectionstrings property
of the configurationtianager class, or the Settings class generated by Visual Studio. Maintain the actual
values into the app. config or web. config (and most definitely not in a custom configuration store).
Build with the highest warning level (AV2210) @
Configure the development environment to use Warning Level 4 for the C# compiler, and enable the option
‘Treat warnings as errors . This allows the compiler to enforce the highest possible code quality.
Properly fill the attributes of the AssemblyInfo. cs file (AV2215) ©
Ensure that the attributes for the company name, description, copyright statement, version, etc. are filled,
(One way to ensure that version and other fields that are common to all assemblies have the same values, is to
move the corresponding attributes out of the AssenblyInfo.cs into a Solutiontnfo.cs file that is shared by
all projects within a solution
Avoid LINQ for simple expressions (AV2220) ©
Rather than:
var query = from item in itens where iten.Length > @ select item;
prefer the use of extension methods from the System. Ling namespace:
var query = items.Where(i => i.Length > 0);Since LINQ queries should be written out over multiple lines for readability, the second example is a bit more
readable.
Use Lambda expressions instead of delegates (AV2221) @
Lambda expressions provide a much more elegant alternative for anonymous delegates. So instead of:
Customer customer = Array.Find(custoners, delegate(Custoner ¢)
{
return c.Nane
Ds
use a Lambda expression:
Customer customer = Array.Find(custorers, ¢ => c.Name
‘Ton*)5
Or even better:
var customer = customers.there(c => c.Nane
Only use the dynamic keyword when talking to a dynamic object (AV2230) @
‘The dynamic keyword has been introduced for working with dynamic languages. Using it introduces a serious
performance bottleneck because the compiler has to generate some complex Reflection code.
Use it only for calling methods or members of a dynamically created instance class (using the Activator) as
an alternative to Type .GetProperty() and Type.Gettethod(), or for working with COM Interop types.
Favor async/await over the Task (AV2235) @
Using the new C# 5.0 keywords results in code that can still be read sequentially and also improves
maintainability a lot, even if you need to chain multiple asynchronous operations. For example, rather than
defining your method like this:
public Task GetDataasyne(),
«
return MyWebService.FetchbataAsync()
-Continueliith(t => new Data(t-Result));
define it like this:
public async Task GetDatarsyne()
{
var result = await MyvebService.FetchDataasyne();
return new Data (result);
y
Tip: Even if you need to target .NET Framework 4.0 you can use the async and await keywords. Simply install
the Async Targeting Pack.9. Documentation Guidelines
Write comments and documentation in US English (AV2301) ©
Document all public, protected and internal types and members (AV2305) ©
Documenting your code allows Visual Studio to pop-up the documentation when your class is used
somewhere else. Furthermore, by properly documenting your classes, tools can generate professionally
looking class documentation.
Write XML documentation with other developers in mind (AV2306) @
Write the documentation of your type with other developers in mind. Assume they will not have access to the
source code and try to explain how to get the most out of the functionality of your type.
Write MSDN-style documentation (AV2307) ©
Following the MSDN online help style and word choice helps developers find their way through your
documentation more easily.
Tip: The tool GhostDoc can generate a starting point for documenting code with a shortcut key.
Avoid inline comments (AV2310) ©
I you feel the need to explain a block of code using a comment, consider replacing that block with a method
with a clear name.
Only write comments to explain complex algorithms or decisions (AV2316) @
Try to focus comments on the why and what of a code block and not the how. Avoid explaining the
statements in words, but instead help the reader understand why you chose a certain solution or algorithm
and what you are trying to achieve, If applicable, also mention that you chose an alternative solution because
you ran into a problem with the obvious solution.
Don't use comments for tracking work to be done later (AV2318) ©
Annotating a block of code or some work to be done using a TODO or similar comment may seem a
reasonable way of tracking work-to-be-done. But in reality, nobody really searches for comments like that.
Use a work item tracking system such as Team Foundation Server to keep track of leftovers,10. Layout Guidelines
Use a common layout (AV2400) ©
‘© Keep the length of each line under 130 characters,
'* Use an indentation of 4 whitespaces, and don't use tabs
‘+ Keep one whitespace between keywords like if and the expression, but don't add whitespaces after (
and before ) such as: if (condition == null)
‘+ Add a whitespace around operators like +,
'* Always follow the keywords if, else, do, while, for and foreach with opening and closing braces, even
though the language does not require it.
‘+ Always put opening and closing braces on a new line,
‘© Don't indent object initializers and initialize each property on a new line, so use a format like this:
var dto = new Consunerdto()
£
1d = 123,
Nane = "Microsoft",
Partnership = PartnerShip.Gold
»
‘+ Don't indent lambda statements and use a format like this:
methodThatTakesAnAction.Do(x =>
{
11 do something like this
‘Put the entire LING statement on one line, or start each keyword at the same indentation, like this:
var query = from product in products where product.Price > 1@ select product;
or
var query
fron product in products
lihere product.Price > 10
select product;
‘+ Start the LINQ statement with all the fron expressions and don't interweave them with restrictions.
‘= Add parentheses around every comparison condition, but don’t add parentheses around a singular
condition. For example if (Istring.TsNullorémpty(str) && (str |= “new"))
‘+ Add an empty line between multi-line statements, between members, after the closing parentheses,
between unrelated code blocks, around the #region keyword, and between the using statements of
different root namespaces.Order and group namespaces according to the company (AV2402) ©
// Microsoft namespaces are first
using System;
using System.Collections;
using System.xHL;
// Then any other namespaces in alphabetic onder
using AvivaSolutions.Business;
using AvivaSolutions. standard;
using Telerik.webControls
using Telerik. Ajax;
Place members in a well-defined order (AV2406) @
Maintaining a common order allows other team members to find their way in your code more easily. In
general, a source file should be readable from top to bottom, as if reading a book, to prevent readers from
having to browse up and down through the code file.
|. Private fields and constants (in a region)
- Public constants
3. Public read-only static fields
. Factory Methods
. Constructors and the Finalizer
. Events
Public Properties
Other methods and private properties in calling order
Be reluctant with #regions (AV2407)@
Regions can be helpful, but can also hide the main purpose of a class. Therefore, use #regions only for:
‘Private fields and constants (preferably ina Private Definitions region).
+ Nested classes
‘+ Interface implementations (only if the interface is not the main purpose of that class)A1. Important Resources
The companion website
This document is part of an effort to increase the consciousness with which Ct developers do their daily job
on a professional level. Therefore I've started a dedicated CodePlex site that can be found at
www.csharpeodingguidelines.com,
In addition to the most up to date version of this document, you'll find:
‘+ Acompanion quick-reference sheet
Visual Studio 2010/2012 Rule Sets for different types of systems.
‘+ ReSharper layout configurations matching the rules in chapter 10,
+ Aplace to discuss C# coding quality.
Useful links
In addition to the many links provided throughout this document, I'd ike to recommend the following books,
articles and sites for everyone interested in software quality:
‘© Code Complete: A Practical Handbook of Software Construction (Steve McConnel)
One of the best books I've ever read. It deals with all aspects of software development, and even though
the book was originally written in 2004 you'll be surprised when you see how accurate it still is. | wrote a
review in 2009 if you want to get a sense of its contents.
‘© The Art of Agile Development James Shore)
Another great all-encompassing trip through the many practices preached by processes like Scrum and
Extreme Programming. If you're looking for a quick introduction with a pragmatic touch, make sure you
read James's book.
‘© Applying Domain-Driven Design and Patterns: With Examples in C# and .NET (immy Nilsson)
‘The book that started my interest for both Domain-Driven Design and Test-Driven Development. It's one
of those books that | wished | had read a few years earlier. It would have spared me from many mistakes.
* Jeremy D. Miller's Blog
Although he is not that active anymore, in the last couple of years he has written some excellent blog
posts on Test-Driven Development, Design Patterns and design principles. I've learned a lot from his real-
life and practical insights.
‘© LING Framework Design Guidelines
A set of rules and recommendations that you should adhere to when creating your own
implementations of IQueryable.
Best Practices for c## async/await
‘The rationale and source of several of the new guidelines in this document, written by Jon Wagner.