Click here to Skip to main content
15,904,024 members
Articles / Web Development / ASP.NET
Article

C# Coding Standards and Best Programming Practices

Rate me:
Please Sign up or sign in to vote.
3.50/5 (123 votes)
5 Dec 20047 min read 453.2K   178   67
Anybody can write code! With a few months of programming experience, you can write "working applications." Making it work is easy, but doing it the most efficient way requires more work than just making it work!

Introduction

Believe it: majority of the programmers write "working code," but not "efficient code." As we mentioned in the beginning of this tutorial, do you want to become the "Most Valued Professional" of your company? Writing "efficient code" is an art that you must learn and practice.

Naming Conventions and Standards

  • Pascal casing: the first character of all words is upper case and the other characters are lower case.
  • Camel casing: the first character of all words, except the first word, is upper case and other characters are lower case.

Use Pascal casing for class names:

C#
public class HelloWorld
{
  ...
}

Use Pascal casing for method names:

C#
public class HelloWorld
{
  void SayHello(string name)
  {
    ...
  }
}

Use Camel casing for variables and method parameters:

C#
public class HelloWorld
{
 int totalCount = 0;
 void SayHello(string name)
 {
  string fullMessage = "Hello " + name;
  ...
 }
}

Do not use Hungarian notation to name variables. In earlier days, most programmers liked it: having the data type as a prefix for the variable name and using m_ as the prefix for member variables, e.g:

C#
string m_sName;
int nAge;

However, in .NET coding standards, this is not recommended. Usage of data type and M_ to represent member variables should not be done. All variables should use Camel casing. Use meaningful, descriptive words to name variables:

  • Do not use abbreviations. Use name, address, salary etc. instead of nam, addr, sal.
  • Do not use single character variable names like i, n, x, etc. Use names like index and temp.

One exception in this case would be variables used for iterations in loops:

C#
for ( int i = 0; i < count; i++ )
{
 ...
}

If the variable is used only as a counter for iteration and is not used anywhere else in the loop, many people still like to use a single char variable (i) instead of inventing a different suitable name.

  • Do not use underscores (_) in variable names.
  • Namespace names should follow the standard pattern.
<company name>.<product name>.<top level module>.<bottom level module>

File name should match with class name. For example, for the class HelloWorld, the file name should be helloworld.cs (or helloworld.vb).

Indentation and spacing: use TAB for indentation. Do not use spaces.

Comments should be in the same level as the code. Curly braces ( {} ) should be in the same level as the code outside the braces. Use one blank line to separate logical groups of code.

C#
bool SayHello (string name)
{
  string fullMessage = "Hello " + name;
  DateTime currentTime = DateTime.Now;
  string message = fullMessage + ", the time is : " + 
                  currentTime.ToShortTimeString();
  MessageBox.Show ( message );
  if ( ... )
  {
  // Do something
  // ...
  return false;
  }
  return true;
}

This code looks better than the code shown above:

C#
bool SayHello ( string name )
{
  string fullMessage = "Hello " + name;
  DateTime currentTime = DateTime.Now;
    string message = fullMessage + ", the time is : " + 
    currentTime.ToShortTimeString();
  MessageBox.Show ( message );
  if ( ... )
  {
    // Do something
    // ...
   return false;
 }

  return true;
}

There should be one and only one single blank line between each method inside the class. The curly braces should be on a separate line and not in the same line as if, for, etc.

Good:

C#
if ( ... )
{
 // Do something
}

Not good:

C#
if ( ... ) {
 // Do something
}

Use a single space before and after each operator and brackets.

Good:

C#
if ( showResult == true )
{
 for ( int i = 0; i < 10; i++ )
 {
  //
 }
}

Not good:

C#
if(showResult==true)
{
 for(int i= 0;i<10;i++)
 {
  //
 }
}

Good Programming Practices

Avoid having too-large files. If a file has more than 300-400 lines of code, you must consider refactoring the code into helper classes. Avoid writing very long methods. A method should typically have 1-25 lines of code. If a method has more than 25 lines of code, you must consider refactoring it into separate methods. The method's name should tell what it does. Do not use misleading names. If the method name is obvious, there is no need of documentation explaining what the method does.

Good:

C#
void SavePhoneNumber ( string phoneNumber )
{
  // Save the phone number.
}

Not good:

C#
// This method will save the phone number.
void SaveData ( string phoneNumber )
{
 // Save the phone number.
}

A method should do only "one job." Do not combine more than one job in a single method, even if those jobs are very small.

Good:

C#
// Save the address.
SaveAddress (  address );

// Send an email to the supervisor to inform that the address is updated.
SendEmail ( address, email );

void SaveAddress ( string address )
{
 // Save the address.
 // ...
}

void SendEmail ( string address, string email )
{
 // Send an email to inform the supervisor that the address is changed.
 // ...
}

Not good:

C#
// Save address and send an email to the supervisor
// to inform that the address is updated.
SaveAddress ( address, email );
void SaveAddress ( string address, string email )
{
 // Job 1.
 // Save the address.
 // ...
// Job 2.
 // Send an email to inform the supervisor that the address is changed.
 // ...
}

Use the C# or VB.NET specific types, rather than the alias types defined in the System namespace.

Good:

C#
int age;
string name;
object contactInfo;

Not good:

C#
Int16 age;
String name;
Object contactInfo;

Do not hardcode numbers. Use constants instead. Do not hardcode strings. Use resource files. Avoid using many member variables. Declare local variables and pass them to methods instead of sharing a member variable between methods. If you share a member variable between methods, it will be difficult to track which method changed the value and when. Use enum wherever required. Do not use numbers or strings to indicate discrete values.

Good:

C#
enum MailType
 {
  Html,
  PlainText,
  Attachment
 }
 void SendMail (string message, MailType mailType)
 {
  switch ( mailType )
  {
   case MailType.Html:
    // Do something
    break;
   case MailType.PlainText:
    // Do something
    break;
   case MailType.Attachment:
    // Do something
    break;
   default:
    // Do something
    break;
  }
 }

Not good:

C#
void SendMail (string message, string mailType)
{
  switch ( mailType )
  {
   case "Html":
    // Do something
    break;
   case "PlainText":
    // Do something
    break;
   case "Attachment":
    // Do something
    break;
   default:
    // Do something
    break;
  }
}

Do not make the member variables public or protected. Keep them private and expose public/protected properties. Never hardcode a path or drive name in code. Get the application path programmatically and use relative path. Never assume that your code will run from drive C:. You never know; some users may run it from a network or from a Z:.

In the application start-up, do some kind of "self check" and ensure that all required files and dependencies are available in the expected locations. Check for database connections at start-up, if required. Give a friendly message to the user in case of any problems.

If the required configuration file is not found, the application should be able to create one with default values. If a wrong value is found in the configuration file, the application should throw an error or give a message and also should tell the user what the correct values are.

Error messages should help the user to solve the problem. Never give error messages like "Error in Application," "There is an error," etc. Instead, give specific messages like "Failed to update database. Please make sure the login ID and password are correct."

When displaying error messages, in addition to telling what is wrong, the message should also tell what the user should do to solve the problem. Instead of a message like "Failed to update the database," suggest what the user should do: "Failed to update database. Please make sure the login ID and password are correct."

Show short and friendly messages to the user, but log the actual error with all possible information. This will help a lot in diagnosing problems.

Comments

Do not write comments for every line of code and every variable declared. Write comments wherever required. Good, readable code will require very few comments. If all variables and method names are meaningful, that will make the code very readable and it will not need much commenting. Fewer lines of comments will make the code more elegant. However, if the code is not clean/readable and there are fewer comments, that is worse. If you have to use some complex or weird logic for any reason, document it very well with sufficient comments. If you initialize a numeric variable to a special number other than 0, -1, etc., document the reason for choosing that value. The bottom line is: write clean, readable code in such a way that it doesn't need any comments to understand it. Do a spell check on comments and also make sure that proper grammar and punctuation are used.

Exception Handling

Never do a "catch exception and do nothing." If you hide an exception, you will never know if the exception happened or not. In the case of exceptions, give a friendly message to the user, but log the actual error with all possible details about the error, including the time it occurred, the method and class name, etc. Always catch only the specific exception, not generic exceptions.

Good:

C#
void ReadFromFile ( string fileName )
 {
  try
  {
   // read from file.
  }
  catch (FileIOException ex)
  {
   // log error.
   //  re-throw exception depending on your case.
   throw;
  }
 }

Not good:

C#
void ReadFromFile ( string fileName )
{
  try
  {
    // read from file.
  }
  catch (Exception ex)
  {
    // Catching general exception is bad... we will never know whether it
    // was a file error or some other error.

    // Here you are hiding an exception.
    // In this case no one will ever know that an exception happened.
    return "";
  }
}

There's no need to catch the general exception in all your methods. Leave it open and let the application crash. This will help you find most of the errors during the development cycle. You can have an application level (thread level) error handler where you can handle all general exceptions. In the case of an "unexpected general error," this error handler should catch the exception and should log the error, in addition to giving a friendly message to the user before closing the application or allowing the user to "ignore and proceed."

Do not write try-catch in all your methods. Use it only if there is a possibility that a specific exception may occur. For example, if you are writing into a file, handle only FileIOException.

Do not write very large try-catch blocks. If required, write a separate try-catch for each task you perform and enclose only the specific piece of code inside the try-catch. This will help you find which piece of code generated the exception and you can give specific error messages to the user.

You may write your own custom exception classes, if required, in your application. Do not derive your custom exceptions from the base class SystemException. Instead, inherit from ApplicationException.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
Tony is a seasoned .NET developer who recently switched his focus to Windows 8 and SEO. You may visit his technology websites: www.dotnetspider.com and www.techulator.com.

Comments and Discussions

 
GeneralRe: Variable naming Pin
sfawcett6-Dec-04 11:32
sfawcett6-Dec-04 11:32 
GeneralRe: Variable naming Pin
ceb30-May-07 8:49
ceb30-May-07 8:49 
GeneralNot bad. Pin
Robert Kozak5-Dec-04 12:01
Robert Kozak5-Dec-04 12:01 
GeneralRe: Not bad. Pin
Willie Lassiter5-Dec-04 14:24
Willie Lassiter5-Dec-04 14:24 
GeneralRe: Not bad. Pin
Robert Kozak5-Dec-04 14:34
Robert Kozak5-Dec-04 14:34 
GeneralRe: Not bad. Pin
Willie Lassiter5-Dec-04 14:49
Willie Lassiter5-Dec-04 14:49 
GeneralSome good stuff Pin
Michael P Butler5-Dec-04 9:23
Michael P Butler5-Dec-04 9:23 
GeneralRe: Some good stuff Pin
Willie Lassiter5-Dec-04 13:10
Willie Lassiter5-Dec-04 13:10 
Michael P Butler wrote:
Also, I don't like this

T Manjaly wrote:

Comments should explain why the code is doing something, not what the code is doing. A descriptive naming convention is good, but won't help explain why you wrote the code in the first place.


The design (selection of algorithms, approaches and solutions) “should explain why the code is doing something” and, therefore, should not be in the code; it should be in a separate design document.

The original author is more correct here. There was a time when programmers were forced by the compiler to use short non-descriptive variable names, hence the overuse of the variable "i" today, being inherited from Fortran days when the type of a variable was implied by the 1st character of its name, "i - n" (I believe for "int"s as formula translation required a lot of floats.)

Comments in Fortran always took up an entire line, and were almost free in terms of processing, they never made it to the compiler because of the routing of the punch cards. Comments were essential in those days to explain what a programmer was doing. Initial versions of C also had short variable names, and again, during that era, comments are tremendously useful.

Unfortunately, programmers today still have the bad habit of creating non-descript variables names, then trying to use a comment to explain its purpose. Over-commenting is inefficient, because every time you change the code, you obliged to update the comments And if you don't, things can quickly get out of synch. And there's nothing worse than a comment that went from being initially unnecessary to now being irrelevant.

Weaving and intermingling comments tightly into source code makes it very hard for someone to read more than a few lines of real code at a time. This hinders they're ability assist in finding bugs by not being to quickly see the difference between a coder’s intent and his implementation. Sometimes you need to take out all of the comments to get a good overall sense of what's going on.

Proper use of whitespace is a better clarifier of a programmer’s code than comments. What we're looking for is not why the programmer did something, (we can should be able to get that for design docs), we want to know what he did. “Micro” commenting (the trees) is not going to help us see that, we need to look at large units of code (the forest).

A preamble should be used at the beginning of each function or method. Whitespace should be used to create logical grouping of lines of code that work tightly together. Comments should be red flags, and placeholders pointing to areas that need further development. Truly, by only placing comments in areas where the developer thinks his work to be a little shaky, is a better use of a comment ("I'm not sure if this the best way to do this" or "Using a bubble sort here just to get things going."), then throwing them in all of the place littering the logic. If the only way to figure what's going is through the use of comments, then the process is bad and the code's bad (period). Good comments can't fix unreadable code.

We live in a new era of programming today, and method and variable names can be much more expressive. We should encourage the taking advantage of that. The code is the realization of the design, not the comments.

Congrats to the original author.

On an aside, programming today is an international medium. The bias towards "proper" english as the language of dialogue, is probably no important in an informal setting such as this. The message is in the content, not the grammar. This isn't an english class. Again kudos to the author for expressing himself so well in what might be a second language. (I wish I spoke multiple languages.)

GeneralEfficient Code Pin
Fx FIXER5-Dec-04 8:04
Fx FIXER5-Dec-04 8:04 
GeneralRe: Efficient Code Pin
Willie Lassiter5-Dec-04 11:59
Willie Lassiter5-Dec-04 11:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.