C# is about objects, classes, and class methods. The runtime handles memory management so you don’t have to. Your C# code is compiled into an intermediate language and runs on the .NET platform. It’s a language built around productivity; therefore, the compiler does many optimizations so you can write clean, readable code.
There are some general standards that fluent C# writers follow. So, if you’re a developer who’s coming to C# from another programming language, you’ll want to know this stuff too! This post is an introduction to the most important standards and sets you on the course to other resources that can help build your C# prowess.
1. Casing
Naming is hard. And because it’s hard, we don’t want to confound the issue with mixed casing. Every language has its own casing standards. To add to the confusion, many organizations, or even teams, have their own standards. When there’s no standard in place, you might even see a cornucopia of every naming convention in just one page of code?I sure have!
There are three casings generally accepted by C# standards:
- PascalCase: This is for class names, file names, namespace names, ALL method names, and public member names.
- camelCase: This is used for member names that are not publicly accessible.
- UPPER_CASE: You might also think of this as upper snake case. This is only used for constants.
There are some exceptions that exist in the world, and for good reasons.
Names like “Pascal_snake_case” or “snake_case” are sometimes used in unit testing. A descriptive method name such as Should_return_2_when_adding_1_and_1 is much easier to read. That’s the reason for snake casing in unit tests.
Event handlers (a type of method) often include an underscore to separate the target from the action. A classic example is Page_Load in ASP.NET. But this is not Pascal_snake_case. For example, in InputControl_Init, the InputControl is the target and Init is the event.
public class Person { private string firstName; public void SayHello() { Console.WriteLine($"Hello, {this.firstName}!"); } }
In this example, the Person class has a private member variable firstName, which is only accessible from inside this class. The SayHello method is available to any consumer of this class. It accesses the firstName?variable through this?which refers to the current instance of Person.
Another common approach is to prepend the member name with an underscore. Here is the same example using that convention:
public class Person { private string _firstName; public void SayHello(string firstName = null) { Console.WriteLine($"Hello, {firstName ?? _firstName}!"); } }
Using the underscore allows us to omit this when we use the variable. In the example, the method parameter has the same base name as a class member. Therefore, if we use underscore in all member variables, we can avoid accidentally taking the wrong variable.
Note to readers: ?? is a null coalescing operator?a nice shortcut, which means “if null, then.” Also, I used string interpolation in this example since it’s nicer to read than the old string.Format method.
Cardinal Casing Sins of C#
The following casing conventions from other languages will land you in C# hell…
Hungarian Notation
Prepending a type identifier to the name is a no-no!
Hungarian notation invites two problems in C#. For one, the name is misleading when the type changes. Another problem is readability. C# often uses custom types and interfaces. Names such as iDictNames and mpLateFeeMessageProcessor litter the code with extra unintelligibility (what is an “mp” anyway?).
New developers will have to learn the inside naming conventions, which slows down development and introduces operational risk. The IDE gives you plenty of information about the type if and when you need it.
Mixed Conventions
Mixed naming conventions make the program less readable. Be consistent and pay attention to readability. Sure, we’re programming a computer, but the code is really for humans. Computers would be perfectly fine with an entire program of 0s and 1s.
Keep your reader in mind when writing software and use the same casing rules throughout!
To illustrate further, here’s a small program that mixes many conventions:
class aPOORRLY_written-CLASS { public static int METHOD_FindHello_Get() { String LINE = null; for(iCURRENT_ITERATION =0; iCURRENT_ITERATION < _nMaxIterationCount; iCURRENT_ITERATION++) { if(c_MyReadingSomething_CLASS.READALINE(out LINE)){ if(LINE.Contains("Hello")){ response = 1; } return response; } } } private const long _nMaxIterationCount = 100; public static int iCURRENT_ITERATION = 0; public static int response; }
Sorry, that was probably fairly painful even for such a small program. Here’s a clean version:
internal class Hello { public static bool ContainsHello() { for(var i = 0; i < 100; i++) { if(LineReader.ReadLine(out string currentLine) && currentLine.Contains("Hello")) { return true; } } return false; } }
Although this code isn’t that great, it’s much cleaner than the previous example with mixed casing and many other inconsistencies. This next section will help you understand some of the other issues.
2. Formatting
We have formatting conventions for C#, just as we do in any programming language. Formatting has to do with line breaks, indentation, and spacing. True, the IDE will often help with formatting, but it doesn’t do everything for you.
Indentation
Indentation is a hotly contested issue in many languages. Should you use tabs or spaces? This post will not settle the argument. But it will establish that four is the proper number of spaces. Also, if you’re using tabs instead, the tab should be equal to four spaces. These are defaults in Visual Studio, and most IDEs have this preset for C#.
Brackets
In C#, brackets contain the scope of a namespace, class, interface, method, and the like. Brackets are major structural constructs and should always go on their own line. This SO post tries to rationalize it, but honestly, it’s just the common convention.
Terminator
A semicolon terminates a statement. It goes on the same line as the end of the statement, much like a period would. Don’t use extra semicolons?one is enough.
Extra Lines
One extra line is sufficient for separating methods or different sections of a class such as the list of member variables, constructors, and methods.
3. “var” Is Your Friend
Using?var is actually a good idea for all those short-lived variables. It not only saves a lot of redundancy, but it allows for more flexibility in the code. Basically, if you can already see the type based on the variable name, you’re good to go with var! Here are a few examples of var in practice:
var person = new Person(id); var result = await _someApiClient.GetAsync(id, cancellationToken); for(var i = 0; i < max; i++) { // i is implicitly typed } var person = this.personFactory.GetOrCreate(id); this.someDependency.SubmitPerson(person);
4. Always Use Access Modifiers
Always use access modifiers! I know, I know … the default is sometimes what you want: “private” for members, “internal” for classes. But it really does help to be explicit about this. It shows that you were purposeful in your intent.
And while you’re at it, use the lowest necessary modifier. This is equivalent to the principle of least privilege. For example, don’t use protected when private will do. Use protected internal to give access only to subclasses in the assembly. If your class is public and you want to share a member with a subclass outside the assembly, make the member protected. Here’s an example to clarify.
In my assembly, I make a class to read a certain file type.
public FileReader { protected virtual string Read(string location) { // read file and return result } }
You reference my assembly or use NuGet to add it to your project. Since the Read method is protected and virtual, you can not only access it from your own subclass, but you can override it.
5. Use Auto Properties
An auto property creates a backing field for you; you just can’t see it or access it. If you don’t need control over the backing field, don’t create one. Instead, just use the auto property (the shortcut is “prop”). It’ll save a lot of extra code!
public int Count { get; set; }
This is an example of an auto property. It makes your code much cleaner.
6. Where to Declare Variables
Declare variables as close as possible to their use. Some languages work better when you declare all your variables at the start of the function, but the C# compiler doesn’t care. It’ll do the optimal thing no matter where you put the variable. Put the variable close to its use so you have an easier time refactoring your code. In fact, your IDE allows you to highlight the section and right-click (or use Ctrl+.) to do some handy refactoring. If your variable is declared way up top, the refactoring will be overly complex or even downright impossible.
7. Code File Organization
You should only put one class, interface, struct, or enum in a single file. This makes the codebase easier to navigate. For this same reason, you should keep your code organized in folders within the projects.
A project is a collection of files that are related. The namespace should match the project name and the directory path it’s located in. For example, let’s say you have a project called Peoples and a Utilities directory (for, you know, utilities). A utility class to format names would look like this:
namespace Peoples.Utilities { public class NameFormatter { public static string FormatName(Person person) { return $"{person.FamilyName}, {person.GivenName}"; } } }
This utility class would live within the Utilities folder of the Peoples project. Note the use of string interpolation rather than string.Format.
8. Use the Aliases, Jack!
All of the primitive types have aliases. String has string. Int32 has int. Int64 has?long. There are plenty more where those came from, and it’s the preferred way to refer to those types. Use them even if you’re calling a method on the type such as int.Parse.
9. “using” Is Your Friend!
When you have a disposable type, there’s a great little construct built into the language: using. It calls Dispose when the program flow leaves the scope. Here’s an example:
using(var connection = _connectionFactory.Get()) using(var stream = connection.OpenStream()) { // use the connection and the stream }
This example takes a little explanation. For one thing, most people don’t know you can stack the using statements like this. Another thing is when the program flow exits the brackets for any reason both the connection and the stream will be disposed of.
Hopefully, if you have a well-designed connection class, the connection will close prior to being disposed of. In this case, there’s no need to do anything else. This is how C# is meant to be!
Continue the Journey
Clearly, we’ve covered a lot so far, but this is just the beginning. There are so many standards in C# that we can’t possibly cover them all in just one post. Thankfully, we have tools such as Visual Studio to help us while we’re coding.
But there’s an even more powerful way to check your work before it goes out into the wild. Tools like CodeIt.Right offer much more and are continually on top of the latest standards and conventions. Check out some of the Rules Explained posts to see why.
Learn more how CodeIt.Right can help you automate code reviews and improve the quality of your code.
41 Comments. Leave new
StyleCop mandates that constants are PascalCase.
The example at 3. shows ehy the advice is wrong. For both result and the second personvariable, it’s impossible to know what its type is. Use explicit types there! (all IDEs kann do this with a quick keyboard shortcut – so you can write var and then upgrade to understandable code).
H.M.
Sorry for the typos (or tpyos?) …
Just out of curiosity, what part of 3 did you not understand?
I can’t tell what type this returns:
var result = await _someApiClient.GetAsync(id, cancellationToken);
Why do you need to know?
If I wrote this and you read it, it’s probably because you want to understand what it does. You don’t need to know the type in that scenario, only good names which explains what everything does.
On the other hand, if you are to change this, then you need to know what each type can do. But unless this is a well known type to you, what will the type name tell you? You still don’t know what it does, so you have to navigate to the type’s source code.
If your favorite IDE doesn’t support that kind of navigation, then I see why you want the explicit type name. But which IDE for C# programming would that be?
I can’t either. Var is for lazy people!
Since C# vision implies all fields should be private only, and protected and public access should be granted only with Properties, the underscore prefix _privateField is unnecessary. It breaks alphabetical order and introduce noise against readability.
I’m not that good that my code is perfect, or even good at the first tries. That’s why I refactor a lot. Like moving a section to a constructor and maybe back again. Or moving the inside of a method to a new class/constructor. In those cases, the _fieldConvention is a pain, so I dropped it.
Guess what? It didn’t hurt readability at all.
So what are the good reasons to keep it, except for tradition?
Sharing this with my team.
sigh, your style sucks, my style sucks. Ilike blue cars, you like green, it’s crap.
but yours sucks more on so many levels.
var?? really, only for the lazy – please avoid var as much as possible so the next guy well have a little bit of a clue what TF you mean without having to uess by usage (or searching back by class member names). Use “var” in my org and you’ll be looking for another job before morning tea.
declare variables close to where used? no, no, no, absolutely wrong in so many ways, all in 1 place so you know exactly where to look – right at the top (otherwise if it’s used in many places over tens, hundreds of lines??? your idea is… just, well, making life harder for everyone, the original developer included.
“using”, same as above, for lazy/weenies that don’t know how to clean up after themselves. sure it’s fine in little methods and loops that do bugger all, not in a few hundred lines of real life business logic spread over a few or more methods – it’s just a bad idea.
real world, real code: hundreds, thousands of lines, avoid using, never use var, always declare your variables in 1 place.
these ideas: fine for your first “Hello World” program, but when you go out into the real world please don’t.
This is sarcasm, right?
No var? I guess I won’t be applying for a job at your org.
Ok, so his language was a little harsh, but I (and probably 50% of the rest of the coding community) strongly disagree with using var (except, of course, for anonymous types). It seems developers are adamant on one side or the other. The most important thing is to be consistent with whichever style is chosen by your organization. From my experience, it is absolutely essential that the types be explicit, staring developers right in the face, not only to make things easier to understand, but to avoid misuse as well.
Placement of variables is largely a personal preference. I prefer keeping them close as suggested above, and will even go one step further to say than when (if needed) there is a backing variable for a property, that it be defined directly after the property, not before, and definitely not clumped together at the top. Again, this is my opinion.
The use of “using” is not really a personal preference, but more of a language dynamic. All classes that implement IDisposable should be put in a using block. Likewise, any class that doesn’t put such things in a using block should itself implement IDisposable and be sure to dispose of such things. The fact that objects are IDisposable is a hint that there may be some cleanup, even in the event of an exception, so it shouldn’t be seen as a “style” or a “standard”, it is simply what you must do.
Nice article Phil! Articles like this are helpful for the new people becoming professional developers each day.
Nice article. Thank you!.
Would agree with the others here. Number three is not a good idea. ‘Var’ is for the lazy and makes the code harder to read/maintain.
Intellisense called. they said caring about naming conventions is obsolete now.
Private members of classes like service or sth, are with _camelCase
Having different naming convention for constants is a form of Hungarian notation and should not be used. Why would I rename a field if it changes from const to variable or the other way around?
var, it’s not lazyness just stating the obvious that type us usually irrelevant and caller code doesn’t have to change only because the type changes. Ie if an API returns a person why would I care what the type is called? The data is relevant not what the container is called.
Rog, I don’t get why a try-finally block is better than using, can you elaborate?
Rog, I’m sure you misunderstood having variable declarations close to usage. It’s not about fields what are at top of file after class declaration but variables in methods. What is the benefit of listing all variables used in a method after method decalaration, declare only when is needed. If you have methods of hundreds of lines you are doing something terribly wrong, even a 30 lines method is on the too long side. Even a class with hundreds of lines should be split.
And yes, I have a few enterprise applications with millions of LOC behind me ?
“The data is relevant not what the container is called.” Wow! But C# is typed such that the very language itself cares “what the container is called.” Why have a typed system? Should we write all our code to pass around untyped data, or random Tuples or Lists because they contain data? In fact, however, C# is typed, and to be a good programmer in the language you need to understand the type system of the business you are dealing with. If you don’t know it, and don’t care to, then probably you will not end up being the kind of programmer a company wants to trust with the important stuff. And you have to do that learning when reading it. A really good programmer reads code and knows what interfaces are involved, why conversions work or fail, how inheritance is used, what methods can be invoked and what data can participate in them, all because they know “what the container is called.” You can’t do these if you don’t know the types as you read the code. And the key is that, as programmers, we read code. We spend way more time reading code than writing code. That “var” hides the type, makes it very difficult to read code intelligibly. If you agree to live in that world, one future day you will discover that you won’t be certain what the type of a var declaration is but you will need to know it because that is how the language and the C# compiler works.
Are you really such a bad programmer that you can’t understand code that is more terse and uses var. You must work on and write terrible code consider a new career so that I never run into to you.
Terse code is seldom expressive code. The goal of any developer should be to make the job of the next guy to touch the code as easy as possible. Well written code clearly states its intent. It reads like a novel. No time should be spent deciphering obscure abbreviated variable names or trying to figure out what data is returned from a method. Clear, expressive code is more maintainable and that saves time, money, and results in fewer bugs.
On the subject of being a “bad programmer”, the name calling and derision you’re showing are not traits that I would want in anyone working on my team. You might be the most technically proficient dev out there, but you’re a “bad programmer” if you can’t work on a team. The days of coding in a dank basement are over. Respectfully, you should invest some time working on your soft skills Dave. It’ll make you a better dev.
Too me, this is like caring about what alloy your wrench is made of, and not what you can use it for. If you really need to know the type, maybe it’s time for a better name?
I don’t think this is an accurate view. In this example, it is knowing that the type of the thing is wrench, not screwdriver. The two of course under most circumstances are not interchangeable–though I’ve tried under duress to make use of one as another when I didn’t bring the missing one when I started repairs. But if you only knew its contents and that it was something made of iron versus plastic, it could be a wrench or a screwdriver. That would handcuff someone trying to be a carpenter, in a similar way to not understanding the type system handcuffs programmers. 1234 could be the contents found in a string or an address or simply a number, but you do know the type when you use it. My point is simply that we read code 99% of the time often years later, and we write code a very small percent of the time. Why make your job even one small step of type inference harder? Some day you’ll likely debug a line of code (reading it) by putting a break point on a line of code solely for the purpose of hovering over it and learning its type. Aha! It’s a screwdriver!
Seems like different mindsets on how to read code. In the scenario you describe, I would expect
var screwdriver = GetToolSuitableFor(screws)
. The actual type returned could beITool
.Sometimes the return value is very specific, like
Screwdriver
vsWrench
. Othertimes it’s more general likeITool
.In the cases of the more general, explicit type names will not help you much. Ok, so just by reading, I know this is an
ITool
. But what can it do? If I never saw this type until now, the name won’t help me. But from the code I read, I can at least see how it’s used in that particular scenario. If I then see something likestaff.CleanFloorUsing(screwdriver)
, I know something is off. I don’t need the type name for that.Thomas, good example with the screwdriver idea. What is the type returned by the GetTool call? Doubting it would be ITool as you suggest, because it seems that ITool follows convention for names of interfaces, and if so, by definition interfaces can’t be concrete objects. So we have the real type hidden by the use of var.
Now, we are already relying on reading the code: ITool is by C# convention something that as C# developers we immediately understand. That we are being given an implementation of an interface, and we don’t know the type of the object, only that it implements the interface.
Screwdriver is a variable of type ITool that points to an actual instance of something that implements ITool. One argument I make is that those programmers who know the business types and therefore understand the type system, are more valuable than those who don’t. As a reader of the code, I don’t know if it returns a Philips head or a flat-head, or if it is just poorly named by the developer and actually returns a multi-headed tool one setting of which is a screwdriver. I’d have to debug to see what that type actually is (unless it is explicitly typed). I know nothing about its actual concrete type, and that has the potential effect of slowing me down.
If I knew the return type, as I think a really decent programmer would, I would be unlikely to try to pass it to CleanFloorUsing.
I have to both agree and disagree with this part. There are just certain times when using a strongly typed variable is called for. Parsing back and forth between XML and a class is one. It isn’t that you can’t do it with a weakly typed variable, it is that it just makes life more difficult. There are other times when a var is exactly the tool for the job. Personally, I have been programming for long enough that languages didn’t have a var when I started. Everything had to have a type declaration, or at least the languages I worked with, so you learned how to know what you were doing and you gained an understanding how the variables used impacted the underlying operating system. I started with assembly and chip programming, so I go back a ways. Having the ability to use var, or something similar, allows for greater flexibility, but the programmers tend to lose the discipline of really knowing what the full system impact is. That works in modern times where you have huge amounts of ram and large processors, but there are still industries where that doesn’t work. I really don’t think this one is cut and dried.
1999 called and your customers said that they don’t want developers talking endless about standards rather than delivering value.
So it’s 2023 now. How are all your new developers taking to the layout of the features they are working being completely different based on who originally wrote it?
I’m guessing those 1999 guys are still trucking away and finding it much quicker to onboard new developers to a level that contributes value…
Not a thing just install resharper
Hungarian notation serves me good naming the GUI controls. btn and all buttons listed for me. lbl and every static text listed for me. Especially using Visual Studio 2017, it’s code navigation is so inferior to Delphi+GExperts.
Many good points here, but what kind of programmer would I be if I didn’t disagree with some of them?
But why is it so hard to agree? Could it be that all of this boils down to personal style and preferences?
Because I tried to find research on this, but found none. Could it be that none of this matters in the end?
Beautiful article, enjoyed reading it
“But it will establish that four is the proper number of spaces. Also, if you?re using tabs instead, the tab should be equal to four spaces.”
Why? The whole point of using tabs is to allow individuals to user their own preferred indent size. I like 2 character indents, others may like 4; and should there be an odd person on the team that likes 13, that’s fine too. If we use tabs we all see the code as we prefer.
Yes, 4 may be the VS default, but if it was such a magic number VS wouldn’t let us use a different number at all.
Agreed. 2 is the correct number. And if you use tabs like you should, then the mouth-breather that works on the code after you will enjoy his 4 or, God forbid, 8 space indentation.
I agree with “4. Always Use Access Modifiers” except for public on members. Yes, “public” should be used on the containers like class but not on its members. A member of an internal class has internal access even when its declared public. I find this explicit use of public misleading.
Also, when you said “protected internal” I think you meant “private protected”. The modifier “protected internal” extends the access to all classes of the assembly.
I had a boss, at my last job, that thought 6, 7 and 8 were the worst things a programmer could ever do. He would routinely use global variables and, his reply, when asked was that they should always be used for everything to save typing. For 7 he would routinely stack as much code as possible into one file. I tried breaking things up a bit, when one of our files reached over 3500 lines of code, 3 classes and somewhere north of 50 functions. I couldn’t find anything to fix it, I could barely follow the code because it jumped all over the file, and it was a disaster. He lost his mind and told me to put it all back together, he didn’t want to have to find the different files (they were all in the same folder at the time). That leaves number 8. I tried to explain what the difference was, I had examples to show him and to explain the differences. I was left with he didn’t care, we were always to do it without aliases no matter what. I kind of fall one way or the other on that myself. I can see going one way or the other, but to be so stuck that you won’t move that is just nuts. I made it a while with that job as I wanted to make sure my knee jerk reaction to bail because I smelled bad boss on him, but I couldn’t take it and had to leave.
Strongly disagree with ‘4. Always Use Access Modifiers’.
Do the inclusion of
private
really show I’m purposeful? Don’t think so. But do the reduced noise and ceremony help to show my intentions? I think so.Point 7.. NameFormatter.FormatName ? naaa .Format only
How do you all feel about helping a programmer who does not think anything like the way other programmers think? No one else likes the way I like to format code. The way other programmers format code hurts my brain. It takes much more effort to read code formatted in the standard way, so much that I have no brain power left over to think about what the code actually does, since I spend all my energy parsing the code in my head. I just end up sitting there drooling until I can reformat it so I can read it. I feel so alone and isolated. After 30 years in the industry, I have not yet met or read code written by anyone who wants to format things the way that makes sense to me. Would you provide contempt, pity, or support for someone like me?
I’m with you on almost everything except the Hungarian notation when it comes to I. Prefacing a class with a capital “I” tells the developer that it’s an interface. This is a very long standing convention that in my experience 95% of .Net developers follow.