Introduction This coding guidelines document aims to provide a common standard and practices within the organization. This guidelines will help: · Promote code readability · Promote code maintainability · Faster enablement of new resources joining the project · Mitigate bugs The content of this document comes from multiple experiences and different sources. References are noted at the end of this material. In some cases, the statements were copied verbatim from the external sources to preserve the original intent of the author; thus credit is given to the original authors. Developers are encouraged to have a clear, concise, and self-documenting code with the idea in mind that other developers may read and update it.
CIO China Rapid - Coding Standards and Best Practices C#
All through-out of this document, the following set of terminologies will help you understand the coding guidelines.
Wording
Intent
Justification
Do...
This standard or practice should be followed in all cases. If you think that your specific application is exempt, it probably isn't.
These standards are present to mitigate bugs.
Do Not…
This standard or practice should never be applied.
Same as above.
Consider
This standard or practice should be followed in most cases.
These standards are typically stylistic and attempt to promote a consistent and clear style.
Avoid
This standard or practice should not be followed, unless there's reasonable justification.
Same as above.
You can…
This standard or practice can be followed if you want to; it's not necessarily good or bad. There are probably implications to following the practice (dependencies, or constraints) that should be considered before adopting it.
These standards are typically stylistic, but are not ubiquitously adopted.
Filename should follow the name of the public type. For example, if the public class is Container it should follow that the filename is Container.cs.
Each source file should only have one public type. The exception is when the type differs only on the number of generic parameters or when one is nested in the other. Multiple internal types are allowed in the same source file.
The assembly should contain the appropriate property values describing its name, copyright, and so on.
Standard
Example
Set Copyright to Copyright
[assembly: AssemblyCopyright("Copyright Accenture Inc. 2015")]
Set AssemblyCompany to
[assembly: AssemblyCompany("Accenture Incorporated")]
Set both AssemblyTitle and AssemblyProduct to the current sample name
[assembly: AssemblyTitle("CSNamedPipeClient")
[assembly: AssemblyProduct("CSNamedPipeClient")]
By limiting the length of line of codes improves code readability. The maximum line of codes should be set to 130 characters. Break the codes when the line length exceeds 130 characters.
Make sure to only reference assemblies that are being used by the project. In some instances during development, some assemblies/libraries are used but later on new assembly version has become available. Make it a practice to remove unused assemblies/libraries.
Global variables should be passed as parameters to functions. When a global variable needs to be modified, use it either as an output parameter or return a copy of the global variable.
Global variables referenced inside a function or a class alters the state of the global variable without the caller knowing.
The method name, return type and parameter list can take in different forms. When method declaration does not fit in a single line, break the parameter list into several lines. Both types and parameter name should be on the same line and should be aligned under the preceding one. In a similar manner, method calls should follow the same format.
Method Declarations
//Single line method declaration
int DoSomeProcessing(string param1, string param2, string param3);
// Multiple line method declaration
int DoSomeProcessing(string param1, string param2, string param3,
int param4, int param5, int param6);
Method Calls
var result = DoSomeProcessing("param1", "param2", "param3");
var result = DoSomeProcessing("param1", "param2", "param3",
4, 5, 6);
Do declare parameters in certain order
When declaring parameters, all in parameters should come first while out parameters comes last.var result = Method(string a, byte b, out int c, out string d)
Consider using blank line to separate logical group of codes
if ( … )
{
// Do something
// …
return false;
}
return true;
Consider using one and only one single blank line between each method inside the class.
void method1 ( string parameter1 )
{
// Do something
} void method2 ( string parameter1)
{
// Do something
}
Spaces improve readability by decreasing code density. Here are some guidelines for the use of space characters within code:
Space Guideline
Example
No space between method name and parenthesis
CreateFoo();
Single space after a comma
Method(myChar, 0, 1);
No spaces inside bracket
sx = array[index];
Single space before flow control statements
while (x == y)
Single space separates operators
if (x == y)
Do place curly braces on a separate line and not in the same line as if, for etc
if (nameProp == "Computer1")
{
//Do something
}
Do place curly braces in the same level as the code outside the braces
protected int GetAge (string userName)
{
//Do something here
if (userName == "WhosThis")
{
//Do something here
}
}
Coding conventions serve the following purposes:
In short examples that do not include using directives, use namespace qualifications. If you know that a namespace is imported by default in a project, you do not have to fully qualify the names from that namespace. Qualified names can be broken after a dot (.) if they are too long for a single line, as shown in the following example.
var currentPerformanceCounterCategory = new System.Diagnostics. PerformanceCounterCategory();
dofactory
Naming Conventionsdo
use PascalCasing for class names and method names.
public class ClientActivity{
public void ClearStatistics()
{
//...
}
public void CalculateStatistics()
{
//...
}
}
do
use camelCasing for method arguments and local variables.
public class UserLog{
public void Add(LogEvent logEvent)
{
int itemCount = logEvent.Items.Count;
// ...
}
}
do not
use Hungarian notation or any other type identification in identifiers
// Correct
int counter;
string name;
// Avoid
int iCounter;
string strName;
do not
use Screaming Caps for constants or readonly variables
// Correct
public static const string ShippingType = "DropShip";
// Avoid
public static const string SHIPPINGTYPE = "DropShip";
avoid
using Abbreviations. Exceptions: abbreviations commonly used as names, such as Id, Xml, Ftp, Uri
// Correct
UserGroup userGroup;
Assignment employeeAssignment;
// Avoid
UserGroup usrGrp;
Assignment empAssignment;
// Exceptions
CustomerId customerId;
XmlDocument xmlDocument;
FtpHelper ftpHelper;
UriPart uriPart;
do
use PascalCasing for abbreviations 3 characters or more (2 chars are both uppercase)
HtmlHelper htmlHelper;
FtpTransfer ftpTransfer;
UIControl uiControl;
do not
use Underscores in identifiers. Exception: you can prefix private static variables with an underscore.
// Correct
public DateTime clientAppointment;
public TimeSpan timeLeft;
// Avoid
public DateTime client_Appointment;
public TimeSpan time_Left;
// Exception
private DateTime _registrationDate;
do
use predefined type names instead of system type names like Int16, Single, UInt64, etc
// Correct
string firstName;
int lastIndex;
bool isSaved;
// Avoid
String firstName;
Int32 lastIndex;
Boolean isSaved;
do
use implicit type var for local variable declarations. Exception: primitive types (int, string, double, etc) use predefined names.
var stream = File.Create(path);
var customers = new Dictionary();
// Exceptions
int index = 100;
string timeSheet;
bool isCompleted;
do
use noun or noun phrases to name a class.
public class Employee
{
}
public class BusinessLocation
{
}
public class DocumentCollection
{
}
do
prefix interfaces with the letter I. Interface names are noun (phrases) or adjectives.
public interface IShape
{
}
public interface IShapeCollection
{
}
public interface IGroupable
{
}
do
name source files according to their main classes. Exception: file names with partial classes reflect their source or purpose, e.g. designer, generated, etc.
// Located in Task.cs
public partial class Task{
//...
}
// Located in Task.generated.cs
public partial class Task
{
//...
}
do
organize namespaces with a clearly defined structure
// Examples
namespace Company.Product.Module.SubModule
namespace Product.Module.Component
namespace Product.Layer.Module.Group
do
vertically align curly brackets.
// Correct
class Program
{
static void Main(string[] args)
{
}
}
do
declare all member variables at the top of a class, with static variables at the very top.
// Correct
public class Account{
public static string BankName;
public static decimal Reserves;
public string Number {get; set;}
public DateTime DateOpened {get; set;}
public DateTime DateClosed {get; set;}
public decimal Balance {get; set;}
// Constructor
public Account()
{
// ...
}
}
do
use singular names for enums. Exception: bit field enums.
// Correct
public enum Color{
Red,
Green,
Blue,
Yellow,
Magenta,
Cyan
}
// Exception
[Flags]
public enum Dockings{
None = 0,
Top = 1,
Right = 2,
Bottom = 4,
Left = 8
}
do not
explicitly specify a type of an enum or values of enums (except bit fields)
// Don't
public enum Direction : long
{
North = 1,
East = 2,
South = 3,
West = 4
}
// Correct
public enum Direction
{
North,
East,
South,
West
}
do not
suffix enum names with Enum
// Don't
public enum CoinEnum
{
Penny,
Nickel,
Dime,
Quarter,
Dollar
}
// Correct
public enum Coin
{
Penny,
Nickel
,Dime,
Quarter,
Dollar
}
1. **PascalCase**: This is for class names, file names, namespace names, ALL method names, and public member names.
2. **camelCase**: This is used for member names that are not publicly accessible.
3. **UPPER_CASE**: You might also think of this as upper snake case. This is only used for constants.
4. **Pascal_snake_case**: This is used in unit testing, a descriptive method name such as Should_return_2_when_adding_1_and_1 is much easier to read.
public string Name {get; set;}
Name
Case
Variables
camelCase
Class
PascalCase
Constructor
PascalCase
Properties
PascalCase
Delegate
PascalCase
Enum
PascalCase
Arguments in methods
camelCase
Method
PascalCase
Constants
PascalCase
Field
camelCase
To declare an empty method which only returns a view in MVC, we should use the expression body.
//Avoid
public ActionResult Dashboard()
{
return View();
}
//Do
public ActionResult Dashboard() => View();
To check null or empty condition.
//Avoid
var varName = "faisal";
if (varName != null && varName != "")
{
//code
}
//Do
var varName = "faisal";
if (!string.IsNullOrEmpty(varName))
{
//code
}
Use null coalescing expression,
Test test = new Test();
//Avoid
var varName = test.Name != null ? test.Name : "";
//Do
var varName = test.Name ?? "";
Use object initializer,
//Avoid
Test test = new Test();
test.Id = 1;
test.Name = "faisal";
//Do
var test = new Test
{
Id = 1,
Name = "faisal"
};
Use ?. operator,
//Avoid
var empName = "";
Session["Name"] = "Faisal Pathan";
if (Session["Name"] != null)
{
empName = Session["Name"].ToString();
}
else
{
empName = "";
}
//Do
var empName = "";
Session["Name"] = "Faisal Pathan";
empName = Session["Name"]?.ToString() ?? "";
Avoid extra braces,
Note - only work with single line statements.
var count = 10;
//Avoid
if (count > 0)
{
//code
count++;
}
//Do
if (count > 0) count++;
//code
//Avoid
for (int i = 0; i < count; i++)
{
//code
count += 10;
}
//Do
for (int i = 0; i < count; i++) count += 10;
var testList = new List<Test>();
var names = new ArrayList();
//Avoid
foreach (var item in testList)
{
names.Add(item.Name);
}
//Do
foreach (var item in testList) names.Add(item.Name);
Use string interpolation.
Test test = new Test();
//Avoid
var details = string.Format("{0}, you are welcome, Your Id is {1}", test.Name , test.Id + "_emp");
//Do
var details = $"{test.Name}, you are welcome, Your Id is {test.Id}_emp";
New lightweight switchcase with c# 8,
int itemSwitch = 1;
//Good
switch (itemSwitch) {
case 1:
Console.WriteLine("Item 1");
break;
case 2:
Console.WriteLine("Item 2");
break;
case 3:
Console.WriteLine("Item 3");
break;
default:
Console.WriteLine("Default item case");
break;
}
//better
var message = itemSwitch switch
{
1 => Console.WriteLine("Item 1"),
2 => Console.WriteLine("Item 2"),
3 => Console.WriteLine("Item 3") ,
_ => "Default item case"
};
Console.WriteLine(message);
Good layout uses formatting to emphasize the structure of your code and to make the code easier to read. Microsoft examples and samples conform to the following conventions:
Use the default Code Editor settings (smart indenting, four-character indents, tabs saved as spaces). For more information, see Options, Text Editor, C#, Formatting.
Write only one statement per line.
Write only one declaration per line.
If continuation lines are not indented automatically, indent them one tab stop (four spaces).
Add at least one blank line between method definitions and property definitions.
Use parentheses to make clauses in an expression apparent, as shown in the following code.
if ((val1 > val2) && (val1 > val3))
{
// Take appropriate action.
}
Place the comment on a separate line, not at the end of a line of code.
Begin comment text with an uppercase letter.
End comment text with a period.
Insert one space between the comment delimiter (//) and the comment text, as shown in the following example.
// The following declaration creates a query. It does not run
// the query.
Do not create formatted blocks of asterisks around comments.
The following sections describe practices that the C# team follows to prepare code examples and samples.
Use string interpolation to concatenate short strings, as shown in the following code.
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
To append strings in loops, especially when you are working with large amounts of text, use a StringBuilder object.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
Use implicit typing for local variables when the type of the variable is obvious from the right side of the assignment, or when the precise type is not important.
// When the type of a variable is clear from the context, use var
// in the declaration.
var var1 = "This is clearly a string.";
var var2 = 27;
var var3 = Convert.ToInt32(Console.ReadLine());
Do not use var when the type is not apparent from the right side of the assignment.
// When the type of a variable is not clear from the context, use an
// explicit type.
int var4 = ExampleClass.ResultSoFar();
Do not rely on the variable name to specify the type of the variable. It might not be correct.
// Naming the following variable inputInt is misleading.
// It is a string.
var inputInt = Console.ReadLine();
Console.WriteLine(inputInt);
Avoid the use of var in place of dynamic.
Use implicit typing to determine the type of the loop variable in for loops.
The following example uses implicit typing in a for statement.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
Do not use implicit typing to determine the type of the loop variable in foreach loops.The following example uses explicit typing in a foreach statement.
foreach (var ch in laugh)
{
if (ch == 'h')
Console.Write("H");
else
Console.Write(ch);
}
Console.WriteLine();
Note
Be careful not to accidentally change a type of an element of the iterable collection. For example, it is easy to switch from System.Linq.IQueryable to System.Collections.IEnumerable in a foreach statement, which changes the execution of a query.
In general, use int rather than unsigned types. The use of int is common throughout C#, and it is easier to interact with other libraries when you use int.
Use the concise syntax when you initialize arrays on the declaration line.
// Preferred syntax. Note that you cannot use var here instead of string[].
string[] vowels1 = { "a", "e", "i", "o", "u" };
// If you use explicit instantiation, you can use var.
var vowels2 = new string[] { "a", "e", "i", "o", "u" };
// If you specify an array size, you must initialize the elements one at a time.
var vowels3 = new string[5];
vowels3[0] = "a";
vowels3[1] = "e";
// And so on.
Use the concise syntax to create instances of a delegate type.
// First, in class Program, define the delegate type and a method that
// has a matching signature.
// Define the type.
public delegate void Del(string message);
// Define a method that has a matching signature.
public static void DelMethod(string str)
{
Console.WriteLine("DelMethod argument: {0}", str);
}
// In the Main method, create an instance of Del.
// Preferred: Create an instance of Del by using condensed syntax.
Del exampleDel2 = DelMethod;
// The following declaration uses the full syntax.
Del exampleDel1 = new Del(DelMethod);
Use a try-catch statement for most exception handling.
static string GetValueFromArray(string[] array, int index)
{
try
{
return array[index];
}
catch (System.IndexOutOfRangeException ex)
{
Console.WriteLine("Index is out of range: {0}", index);
throw;
}
}
Simplify your code by using the C# using statement. If you have a try-finally statement in which the only code in the finally block is a call to the Dispose method, use a using statement instead.
// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
{
((IDisposable)font1).Dispose();
}
}
// You can do the same thing with a using statement.
using (Font font2 = new Font("Arial", 10.0f))
{
byte charset = font2.GdiCharSet;
}
To avoid exceptions and increase performance by skipping unnecessary comparisons, use && instead of & and || instead of | when you perform comparisons, as shown in the following example.
Console.Write("Enter a dividend: ");
var dividend = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a divisor: ");
var divisor = Convert.ToInt32(Console.ReadLine());
// If the divisor is 0, the second clause in the following condition
// causes a run-time error. The && operator short circuits when the
// first expression is false. That is, it does not evaluate the
// second expression. The & operator evaluates both, and causes
// a run-time error when divisor is 0.
if ((divisor != 0) && (dividend / divisor > 0))
{
Console.WriteLine("Quotient: {0}", dividend / divisor);
}
else
{
Console.WriteLine("Attempted division by 0 ends up here.");
}
Use the concise form of object instantiation, with implicit typing, as shown in the following declaration.
var instance1 = new ExampleClass();
The previous line is equivalent to the following declaration.
ExampleClass instance2 = new ExampleClass();
Use object initializers to simplify object creation.
// Object initializer.
var instance3 = new ExampleClass { Name = "Desktop", ID = 37414,
Location = "Redmond", Age = 2.3 };
// Default constructor and assignment statements.
var instance4 = new ExampleClass();
instance4.Name = "Desktop";
instance4.ID = 37414;
instance4.Location = "Redmond";
instance4.Age = 2.3;
If you are defining an event handler that you do not need to remove later, use a lambda expression.
public Form2()
{
// You can use a lambda expression to define an event handler.
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
// Using a lambda expression shortens the following traditional definition.
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object sender, EventArgs e)
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}
Call static members by using the class name: ClassName.StaticMember. This practice makes code more readable by making static access clear. Do not qualify a static member defined in a base class with the name of a derived class. While that code compiles, the code readability is misleading, and the code may break in the future if you add a static member with the same name to the derived class.
Use meaningful names for query variables. The following example uses seattleCustomers for customers who are located in Seattle.
var seattleCustomers = from customer in customers
where customer.City == "Seattle"
select customer.Name;
Use aliases to make sure that property names of anonymous types are correctly capitalized, using Pascal casing.
var localDistributors =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { Customer = customer, Distributor = distributor };
Rename properties when the property names in the result would be ambiguous. For example, if your query returns a customer name and a distributor ID, instead of leaving them as Name and ID in the result, rename them to clarify that Name is the name of a customer, and ID is the ID of a distributor.
var localDistributors2 =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { CustomerName = customer.Name, DistributorID = distributor.ID };
Use implicit typing in the declaration of query variables and range variables.
var seattleCustomers = from customer in customers
where customer.City == "Seattle"
select customer.Name;
Align query clauses under the from clause, as shown in the previous examples.
Use where clauses before other query clauses to ensure that later query clauses operate on the reduced, filtered set of data.
var seattleCustomers2 = from customer in customers
where customer.City == "Seattle"
orderby customer.Name
select customer;
Use multiple from clauses instead of a join clause to access inner collections. For example, a collection of Student objects might each contain a collection of test scores. When the following query is executed, it returns each score that is over 90, along with the last name of the student who received the score.
// Use a compound from to access the inner sequence within each element.
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
手机扫一扫
移动阅读更方便
你可能感兴趣的文章