DEV Community

Artur Kedzior
Artur Kedzior

Posted on • Edited on

My C# Code Conventions and Style Guide

I like to follow "Modern Microsoft" conventions and styles for C# and dotnet; these are the conventions typically found in modern Microsoft GitHub repos like .NET, EF, etc. They are generally also the defaults within Visual Studio.

I go for standard Microsoft conventions as they would be most popular in the community and would generally be more familiar to new developers joining the team.

1. Boolean Evaluations

๐Ÿ˜€ DO prefer expression operator short-hand syntax.

var success = true;

if (success)
{
    // do if true
}

if (!success)
{
    // do if not true
}
Enter fullscreen mode Exit fullscreen mode

Why: Consistent with Microsoftโ€™s .NET Framework and makes code simpler, more concise, and easier to read.

๐Ÿ˜ก DO NOT use long form operator syntax:

var success = true;

if (success == true)
{
    // do if true
}

if (success == false)
{
    // do if not true
}
Enter fullscreen mode Exit fullscreen mode

2. Abbreviation Casing

๐Ÿ˜€ DO prefer PascalCase for a abbreviations of any length found within member names:

public DateTime CreatedUtc { get; set; }
public string SqlConnection { get; set; }
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜ก DO NOT UPPERCASE abbreviations:

public DateTime CreatedUTC { get; set; }
public string SQLConnection { get; set; }
Enter fullscreen mode Exit fullscreen mode

Why: Consistent with Microsoftโ€™s .NET Framework and easier to read.

3. Conditional and Loop Brackets

๐Ÿ˜€ DO always include brackets around single-line conditional and loop statements:

if (true)
{
    DoSomething():
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜ก DO NOT omit brackets:

if (true)
    DoSomething();
Enter fullscreen mode Exit fullscreen mode

Why: It makes the scope of the statements clearer and avoids future issues if those statements are expanded.

4. Var Keyword

๐Ÿ˜€ DO always prefer using the var keyword instead of the
explicit type:

var option = new CookieOptions();
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜ก DO NOT use the explicit type:

CookieOptions option = new CookieOptions();
Enter fullscreen mode Exit fullscreen mode

Why: It simplifies the code and isnโ€™t any less understandable.

5. LINQ Single vs Where

๐Ÿ˜€ DO always prefer using the Where function instead of the Single :

var order = await DbContext.Orders
   .Where(x => x.Id == id)
   .Where(x => x.Status == OrderStatus.Created)
   .Where(x => x.Customer.Id == customerId)
   .SingleAsync(cancellationToken);
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜ก DO NOT use the explicit type:

var order = await DbContext.Orders
  .SingleAsync(x => x.Id == id && x.Status == OrderStatus.Created && x.Status == OrderStatus.Created, cancellationToken);
Enter fullscreen mode Exit fullscreen mode

Why: It improves readability of the code.

Thank you for reading!

If you enjoyed this post and want to stay updated, follow me on Twitter for the latest updates and check out my projects on GitHub.

May the code be with you!

Top comments (22)

Collapse
 
ant_f_dev profile image
Anthony Fung

Nice!

Just a few complementary points:

(1). I do this one too. I only use the long form when dealing with nullable Booleans.

(2). I seem to remember an MS guideline that stated initialisms with two letters are ok, e.g. IOException, vs IoException.

(4). With newer .NET versions, it's also possible to do:

CookieOptions option = new();
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rmaurodev profile image
Ricardo

I couldnโ€™t get used with the new() way of declaring stuff. I still prefer var keyword :)

Collapse
 
ant_f_dev profile image
Anthony Fung • Edited

I know what you mean. I mostly use var to declare values returned from methods as variables. And so for consistency, I also prefer var to new().

Collapse
 
kedzior_io profile image
Artur Kedzior • Edited

The important is that both are valid, both have no performance implications and both serve to improve readability to different people with different preferences.

Collapse
 
kedzior_io profile image
Artur Kedzior • Edited

@ant_f_dev these are good points. As for the 4th I tend to use new() almost always when initiating class property that requires a default object instance.

For example:

private readonly Dictionary<string, string> _customHeaders = new();

taken from my APIClient used for integration testing where I need to set some custom headers.

Collapse
 
ant_f_dev profile image
Anthony Fung

Ah yes - good call. That makes sense too, as it's not possible to use var at the class level.

Collapse
 
davidpeckuk profile image
David Peck

I cannot understand the preference for !success. It is too easy to miss the exclamation mark. Usually randomly is preferred to being concise but most senior developers

Collapse
 
davidpeckuk profile image
David Peck

To be clear Iโ€™m aware that Iโ€™m in the minority with this one

Collapse
 
kedzior_io profile image
Artur Kedzior

To me it was never an issue but again this is a personal preference and so everyone should use what they feel is more readable to them.

Collapse
 
rexmingla profile image
Tim

Iโ€™m the same as you. Then I ran a poll in the office and everyone else prefers the shorter form :(

Collapse
 
kedzior_io profile image
Artur Kedzior

Yep, different people different preference. However, I can tell you that I have very little code or almost none that checks for false like this !success. I tend to always revert the statement, so let's say a void method would quit immediately or continue execution.

So instead of this:

public void DoSomething()
{
 if (!success) 
 {
   // do something 
 }
}
Enter fullscreen mode Exit fullscreen mode

I would write:

public void DoSomething()
{
 if (success) 
 {
   return;
 }
 // do something 
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
odalet profile image
odalet • Edited

I mostly agree with your guidelines although:

  • I do prefer avoiding curly braces when I can for terseness purpose, but that's a personal preference
  • I wouldn't go with #5 for performance reason: if the input collection is large enough, I think chaining several linq calls where only one call would make it can have a serious impact. I'm pretty sure the compiler will not be able to optimize away all those calls into the second form. If for readability, I'd simply indent the complex filter over several lines.
Collapse
 
kedzior_io profile image
Artur Kedzior • Edited

if the input collection is large enough, I think chaining several linq calls where only one call would make it can have a serious impact.

Well if fetching collection that large becomes a problem using LINQ, most likely the feature is not well designed or something else should be used like Dapper.

In 99% of the cases it has insignificant performance impact as multiple Where conditions are combined together so there is a single interattion for all. The compiler will be able to cope with it.

Here is a reference the LINQ source code of Where method:
referencesource.microsoft.com/#Sys...

Oh and that 99% of cases apply to in memory collections only. In my example I'm querying from database which has absolutely no difference as LINQ builds an expression tree.

Collapse
 
odalet profile image
odalet

Right, I had overlooked the fact this wasn't linq to objects. I agree that for simple code as in your example, my way of doing things wouldn't be noticeably quicker. However, recently I had to rewrite a huge pile of dung linq to objects for performance reason. The main culprit was some group by and a select many (if I remember correctly) deeply nested on layers of looping over dictionaries... Then I still think that in such a degenerate case, getting rid of a few method calls and object instantiations in the inner most part can be worth it.
Now if I'm being honest, I guess I simply prefer terseness...

Collapse
 
anotherrios profile image
AnotherRios • Edited

I firmly maintain var is a needless abomination and

CookieOptions option = new ();

Enter fullscreen mode Exit fullscreen mode

Gives you all the alleged benefits with none of the ambiguity or inconsistency.

Collapse
 
someofthethings profile image
Peter Carter • Edited

CookieOptions option = new(); is much better than either of the examples. Var makes the code much less readable in situations (myriad) where the object is not immediately created via a direct right hand side construction. It is a very JavaScripty way of doing things, and over any middle-size codebase and above this pattern is deeply harmful for readability. Apart from the single line if thing, most of the rest seem trivial matters of preference but the var one is an actively damaging dogma that seems to have resulted from a poorly thought-through default linter setting in VS and the inevitable bandwagon it inspired.

If I read this list at work I would think that the person who wrote it clearly wasn't ready for dev lead.

Collapse
 
kedzior_io profile image
Artur Kedzior

Well CookieOptions option = new(); is almost the same as var option = new CookieOptions(); the type is just on a different side. Some like it on one side some like it on another. Again it's a matter of personal taste.

In the example I used the type of the variable is obvious from the right side of the assignment. It makes it shorter and more readable, requires less typing.

I think you went over philosophical with JavaScript analogy. It is absolutely fantastical that C# evolves in the way that actually let's you choose your style and what is more readable to you or the majority of the team.

Collapse
 
ant_f_dev profile image
Anthony Fung

It certainly has evolved a lot since its inception. I look at some of the older projects I have and they look so verbose and rigid.

Collapse
 
odalet profile image
odalet • Edited

Var is especially useful when the right side is a function call: Said function return value can be changed to another type without needing changes at the call sites provided the new and old types are compatible; and if they're not, unlike with javascript, the compiler will complain.
It's invaluable when refactoring huge codebases!
Many languages have gone the 'var' or 'auto' or whatever way of declaring variables without sacrificing strong typing. And I strongly believe that when reading code, one needs to understand the meaning of variables (hence properly naming identifiers is a must), not their exact type. Then when editing, any IDE will straightforwardly provide you with the exact type...

Collapse
 
kedzior_io profile image
Artur Kedzior

You nailed it! Especially with this bit:

I strongly believe that when reading code, one needs to understand the meaning of variables

Collapse
 
someofthethings profile image
Peter Carter • Edited

Of course you need to understand the meaning of the variables: because every piece of code you will read is well structured and properly compartmentalised you will never find clearly delineated type information useful to quickly understand the intended functionality. Said code will of course always be fully commented with absolutely non-arcane variable names and no weird inheritance patterns or etc etc etc...

Of course var can be useful when you only need a quick and dirty refactoring but you know, if you don't understand how to refactor the code such that you retain the left-hand type information without causing compiler issues then I strongly believe you need to understand the variables you are using better (some edge cases with anonymous types accepted)...

Thread Thread
 
kedzior_io profile image
Artur Kedzior

Of course you need to understand the meaning of the variables: because every piece of code you will read is well structured and properly compartmentalised you will never find clearly delineated type information useful to quickly understand the intended functionality. Said code will of course always be fully commented with absolutely non-arcane variable names and no weird inheritance patterns or etc etc etc...

If you have to deal with such a code base, you should glorify the team leader, the PR process and the well established coding guidelines of the company. In such cases lack of type would be very worrying indeed.

Of course var can be useful when you only need a quick and dirty refactoring but you know, if you don't understand how to refactor the code such that you retain the left-hand type information without causing compiler issues then I strongly believe you need to understand the variables you are using better (some edge cases with anonymous types accepted)...

When refactoring the code the IDE is smart enough these days to avoid such issues and even show you variable type if you really want to. In fact IDE such as JetBrains Rider has this feature called "Inlay Hints" that you can turn on/off whenever you like and shows you the type next to the var.

Again, you will rarely find this an issue when your code has a decent structure and it is broken into small self contained pieces.