This article is about to C# coding standards, naming conventions, and best practices.
Use these in your own projects and/or adjust these to your own needs.
Identifier Type
|
Rules for Naming
|
Example
|
Namespaces
|
Pascal Case - Should
start with company namespace, followed by application "layers" as
applicable
|
CoCon.DataServices.Contacts
|
Classes
|
Nouns in Pascal Case
(also use for structs)
|
class Contact
|
Exception Classes
|
Pascal Case and
always end with the suffix Exception
|
Class
CoConGeneralException
|
Interfaces
|
Pascal Case prefixed
by 'I'
|
interface ICustomer
|
Methods
|
Verb or Verb/Noun
pair in Pascal Case
|
GetBackground();
|
Properties
|
Pascal Case - do not
prefix with get or set
|
FirstName
|
Constants
|
All uppercase with
words separated by underscores
|
public const int
MIN_WIDTH = 4;
|
Enum Type
|
Hungarian notation.
|
enuHatType
|
Enum Value
|
All uppercase with
words separated by underscores
|
BOWLER
TOP_HAT
|
Instance Variable
|
Camel Case, prefix
with m - always make private and accessible via a property with the
applicable scope.
|
private int
mCurrentWidth;
|
Local Variable
|
Camel Case.
Always name the
variable appropriately, E.g. What is it being used for.
Avoid using single
characters like "x" or "y" except in FOR loops. Never
name a variable the same as the type.
|
// Wrong
AppUser appUser;
// Correct
AppUser appUserData;
|
Parameters
|
Camel Case
Never name a
parameter the same as the type.
|
public void GetContact(int
contactId);
|
Web Page
|
Pascal Case (Very
important as Visual Studio automatically creates Code Behind class on this
name)
|
ShowResults.aspx
|
Web page controls
|
Camel Case with
control type prefix. For user controls, prefix appropriately named control with
"uc".
|
lbFirstName
txtFirstName
ddCountry
ucPopupDisplay
|
2 Case sensitivity
To avoid confusion, follow these
rules regarding the use of case sensitivity:
- DO NOT create two namespaces with names that differ only by case.
- DO NOT create a method with parameter names that differ only by case.
- DO NOT create methods with names that only differ by a single letter or number.
- DO NOT create a type with property names that differ only by case.
- DO NOT create a type with method names that differ only by case.
- DO NOT create variables with type that differs only by case.
- DO NOT create variables matching data type using a different casing.
3. Coding Style
Consistent layout, format, and organization are keys to creating maintainable code. The following sections describe the preferred way to implement source code in order to create readable, clear, and consistent code that is easy to understand and maintain.
3.1 Formatting
Consistent layout, format, and organization are keys to creating maintainable code. The following sections describe the preferred way to implement source code in order to create readable, clear, and consistent code that is easy to understand and maintain.
3.1 Formatting
- Never declare more than 1 namespace per file.
- Avoid putting multiple classes in a single file.
- Always place curly braces ({ and }) on a new line.
- Always use curly braces ({ and }) in conditional
statements.
Example
if (contactCount ==
0)
{
// code for true case
}
else
{
// code for false case
}
{
// code for true case
}
else
{
// code for false case
}
- Always put parenthesis around all clauses in if
statements.
Example
Bad
if (contactCount == 0 && retrievingData)
{
}
Good
if ((contactCount == 0) &&
(retrievingData))
{
}
- Never make method calls within clause of if statements
Example
Bad
if (GetContacts().Count == 0)
{
}
Good
List<Contact> contactList = GetContacts();
if (contactList.Count == 0)
{
}
- Do not use elseif to string if statements together.
- Always use a Tab & Indention size of 2, inserted as spaces.
- Declare each variable independently – not in the same
statement.
Example
Bad
string firstName, lastName;
Good
string firstName
string lastName;
- Place namespace "using" statements together at the top of file. Group .NET namespaces above custom namespaces. Organize these namespaces alphabetically. NOTE: Visual Studio provides tools to sort using statements in the desired order.
- Group internal class implementation by type in the following order using #region statements:
- Attributes
- Constructors
- Properties
- Methods
- Order declarations within type groups based upon access modifier and visibility:
- Public
- Protected
- Internal
- Private
- Order methods within the public/protected/private sections alphabetically.
- Segregate interface Implementation by using #region statements.
- Recursively indent all code blocks contained within braces. NOTE: Visual Studio support formatting code by Edit/Advanced/Format Code (or control-K, control-D). This requires setting the Editor tabbing and spacing as indicated above.
- Use white space (CR/LF, Tabs, etc) liberally to separate and organize code.
- Avoid declaring multiple attribute declarations within
a single line. Instead stack each attribute as a separate declaration.
This is required in all scopes (assembly, type, method, member, parameter,
etc.)
Example
Bad
[Attribute1] [Attribute1] [Attribute1]
publicclassMyClass
{
}
Good
[Attribute1]
[Attribute1]
[Attribute1]
publicclassMyClass
{
}
- The this and base keywords should be used when needed to specify the namespace of an object used, and not as part of general practice.
- If in doubt, always err on the side of clarity and consistency.
- Parameters in method declarations should be on separate
lines and all parameters should be left aligned.
Example
publicstaticvoid Update(Contact contactData,
IDbConnection dbConn,
IDbTransaction dbTrans)
{
}
- Parameters in method calls should be on separate lines
with all parameters left aligned.
Example
Contact.Update(contactData,
dbConn,
dbTrans);
- Do not insert spaces in parameter list for method
declarations or method calls NOTE: This behavior is configurable in Visual
Studio.
Example
Contact.Update(contactData,
dbConn,
dbTrans);
Rounded Rectangular Callout: Rounded Rectangular
Do not insert spaces here Callout: Or here
- Declare all variables at the beginning of a method. Do not place declarations throughout the method body.
- Place a "using" or "imports"
statement at the beginning of each class to avoid having to type a fully
qualified namespace/class/method name to invoke a method:
Example
Bad
CoCon.SystemFramework.LoggerServices.Write(…);
Good
using CoCon.SystemFramework;
…
LoggerServices.Write(…);
- Put parenthesis around the entire entity being cast.
Example
enuHatType hatType = (enuHatType)(DBService.GetInt(dataRow,
COLUMN_NAME,
DEFAULT_VALUE));
- A parent class is responsible for updating the relationship table with its child/included objects, its child objects do not address that relationship.
3.2 Commenting
- All comments should be written in U.S. English.
- Use // or /// but do NOT use /* */.
- Commented out code should be code that will be soon deleted, and marked with a TODO:.
- Do not "flowerbox" comment blocks.
Example
Bad
// ********************************
// Comment block
// ********************************
Good
Good
// ********************************
// Comment block
- Use inline-comments to explain assumptions, known issues, and algorithm insights.
- Do not use inline-comments to explain obvious code. Well written code is self documenting.
- Use "TODO:" task list tokens to mark
incomplete methods or sections.
Example
// TODO: handle validation errors
- Do NOT use "HACK" or "UNDONE" task list tokens. Other tokens may be added with team consensus and they are added to this document to define how they are to be used.
- Always apply c# comment-blocks (///) to classes. Class comment block should include the following.
- Required
- Summary (<summary>) - used to define what the
class is used for
- Optional
- Remarks (<remarks>) - used to provide further explanation of the class use.
- Always apply c# documentation comment blocks (///) to constructors, properties, and methods. Comment blocks should include the following sections.
- Required
- Summary (<summary>) - used to define what the
constructor, property, or method is used for.
- Conditional
- Param (<param name="theNameOfTheParameter">) - Required for each parameter passed to the constructor or method. Should include what the parameter its primary use.
- Returns (<returns>) - Required for any method that returns a value. Should describe the returned data type and a description of what it is set to.
- Optional
- Remarks (<remarks>) - Used to convey more information about the method. This may include pseudo code for complicated methods.
- Exception (<exception
cref="CoConGeneralException">) - Used to indicate what
exception(s) are potentially throw by the method.
- Additional c# document comment blocks guidelines
- Add a blank line between the sections for readability.
- Sections should be ordered as follows:
- Summary
- Param
- Return
- Remark
- Exception
3.3 VS .Net Environment Setup
- Select Tools/Options
- Select Text Editor
- Select All Languages/Tabs and set the following:
- Indenting: Block
- Tab Size: 2
- Tab Indent Size: 2
- Select "Insert Spaces"
- Select C#/Formatting/General – check all checkboxes
- Select C#/Formatting/Indentation – check all checkboxes except "Indent open and close braces" which should be unchecked.
- Select C#/Formatting/New Lines – check all checkboxes
4. Language Usage
4.1 Variables and Types
4.1 Variables and Types
- Do not omit access modifiers. Explicitly declare all
identifiers with the appropriate access modifier instead of allowing the
default.
Example
// Bad!
void
WriteEvent(string message)
{
}
// Good!
privatevoid
WriteEvent(string message)
{
}
- Declare all variables at the beginning of a method and initialize object variables to null. Scalar variables do not need to be initialized at declaration.
- Use the simplest data type, list, or object required. For example, use int over long unless you know you need to store 64 bit values.
- Always use the built-in data type aliases, not the .NET
common type system (CTS).
Example - short not System.Int16
- int not System.Int32
- long not System.Int64
- string not System.String
- Declare instance variables as private. Use properties to provide access to them with public, protected, or internal access modifiers as applicable.
- enum - should be int unless you have an explicit need for long.
- Avoid using inline numeric literals (magic numbers). Instead, use a constant or enum.
- Avoid declaring inline string literals. Instead use Constants, Resources or other data sources.
- Use the @ prefix when initializing string constants or
variables instead of escaped strings.
Example
Bad
private const string PATH = "C:\\Projects\\CoCon\\";
Good
private const string PATH = @"C:\Projects\CoCon\";
- For string template construction, use String.Format()
- For string concatenation being performed more than once on a string, use StringBuilder
- Avoid concatenating strings inside a loop. Use StringBuilder if concatenation is required inside the loop.
- Do not compare strings to String.Empty or "" to check for empty strings. Use String.IsNullOrEmpty or myString.Length == 0
- When comparing one string to another, use myString1.Equals(myString2)
- Avoid hidden string allocations, especially within a loop. NOTE: Strings are inmutable so changing the value of a string actually allocates a new string.
- Do not invoke methods in conditional statements
- Avoid creating recursive methods. Any perceived need for a recursive method must be reviewed by the team before implementation.
4.2 Exception Handling
- Do not use try/catch blocks for flow-control.
- Only catch exceptions when you can add value such as context information to the exception.
- Never declare an empty catch block. This results in "dumping the exception on the floor."
- Avoid nesting a try/catch within a catch block. Any perceived need for nested try/catch blocks must be reviewed by the team before implementation.
- Use exception filters where possible.
Example
catch(CoConGeneralException
exc )
{
//do actions
}
catch(Exception
exc)
{
//do actions
}
- Order exception filters from most to least derived exception type.
- Avoid re-throwing an exception. Allow it to bubble-up if you can add no additional data to help with the debugging.
- Never use "e" as the variable for the exception. Use "exc" or an abbreviated version of the exception being caught.
- If re-throwing an exception, omit the exception
argument from throw statement to preserve the original call stack.
Example
// Bad
catch(Exception
exc)
{
Log(exc);
throw
exc;
}
// Good
catch(Exception
exc)
{
Log(exc);
throw;
}
- Only use the finally block to release resources from a try statement.
- When retrieving a DataTable, and expecting only zero or
one rows, throw a Exception if the Rows.Count value is anything else
Example
dataTable = DBService.ExecuteQuery(sql);
switch
(dataTable.Rows.Count)
{
case 0:
//
process no rows case
break;
case 1:
// process
single row case
break;
default:
ArgumentException exc = newArgumentException("Error
message here");
throw exc;
}
}
5. Database
Given that data classes will be using inline, dynamic, parameterized SQL for database access, the following sets of guidelines will be followed.
Given that data classes will be using inline, dynamic, parameterized SQL for database access, the following sets of guidelines will be followed.
- Use the SELECT constant to select columns. Do not use SELECT *
- Always declare all column names as constants.
- Always use parameters in a SQL statement instead of inline variables for all data.
- When transactions are used, each Begin must be matched with a Rollback/Commit.
- For complex statements, please feel free to consult a DBA for query optimization advice.
No comments:
Post a Comment