Common Structure of C# Programs
A C# program can consist of one or more files. Each file can contain zero or more namespaces. In addition to other namespaces, a namespace can also contain classes, structures, interfaces, enumerations, delegates and other types. Here is the backbone of a C# program that contains all these elements.
// A skeleton of a C# program using System; namespace YourNamespace { class YourClass { } struct YourStruct { } interface IYourInterface { } delegate int YourDelegate(); enum YourEnum { } namespace YourNestedNamespace { struct YourStruct { } } class YourMainClass { static void Main(string[] args) { //Your program starts here... } } }
C# coding convention
C# Language Specification Undefined encoding standards. However, Microsoft develops samples and documents based on the guidelines in this topic.
The encoding convention can achieve the following purposes:
- They create a consistent look for the code to ensure that the reader focuses on content rather than layout.
- They allow readers to understand the code faster by assumptions based on previous experience.
- They facilitate copying, changing, and maintaining code.
- They showcase C# best practices.
Naming agreement
In short examples that do not include the using directive, use namespace limitations. If you know that namespaces are imported into the project by default, you don't have to fully qualify the name from that namespace. If it's too long for a single line, you can break the qualifying name after the dot (.), as shown in the following example.
var currentPerformanceCounterCategory = new . PerformanceCounterCategory();
You do not have to change the names of objects created by using the Visual Studio Designer tool to make them suitable for other guidelines.
Layout agreement
A good layout uses formatting to emphasize the structure of the code and make the code easier to read. Microsoft examples and samples comply with the following conventions:
- Use the default code editor settings (intelligent indent, 4-character indent, tabs saved as spaces). For more information, see Options, Text Editor, C#, Format Settings.
- Write only one sentence per line.
- Write only one declaration per line.
- If consecutive lines are not automatically indented, indent them into a tab bit (four spaces).
- Add at least one blank line between the method definition and the property definition.
Use brackets to highlight clauses in expressions, as shown in the following code.
if ((val1 > val2) && (val1 > val3)) { // Take appropriate action. }
Comment convention
Put comments on separate lines, not at the end of the line of code.
Comment text in capital letters.
End the comment text with a period.
Insert a 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 asterisk blocks around comments.
Language Code
The following sections describe the practice of C# following to prepare code examples and samples.
String Data Type
Use the + operator to concatenate short strings, as shown in the following code.
string displayName = nameList[n].LastName + ", " + nameList[n].FirstName;
To append strings into a loop, especially when using a lot of text, use the StringBuilder object.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { (phrase); } //("tra" + manyPhrases);
Local variables of implicit types
When the variable type obviously comes from the right side of the assignment, or when the precision type is not important, type the local variable implicitly.
// 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(());
Do not use var when the type is not obviously 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 = ();
Do not rely on variable names to specify the type of variable. It may be incorrect.
// Naming the following variable inputInt is misleading. // It is a string. var inputInt = (); (inputInt);
Avoid using var instead of dynamic.
Use implicit type to determine the type of loop variables in the for and foreach loops.
The following example uses implicit type in the for statement.
var syllable = "ha"; var laugh = ""; for (var i = 0; i < 10; i++) { laugh += syllable; (laugh); }
The following example uses implicit type in the foreach statement.
foreach (var ch in laugh) { if (ch == 'h') ("H"); else (ch); } ();
Unsigned data types
Typically, use int instead of unsigned types. The use of int is common throughout C# and is easier to interact with other libraries when you use int.
Array
Use concise syntax when initializing an array on a 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.
Entrustment
Use concise syntax to create instances of delegate types.
// 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) { ("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);
try-catch and using statements in exception handling
Use the try-catch statement for most exception handling.
static string GetValueFromArray(string[] array, int index) { try { return array[index]; } catch ( ex) { ("Index is out of range: {0}", index); throw; } }
Simplify your code by using C# using statements. If you have a try-finally statement (the only code for the finally block in that statement is a call to the Dispose method), use the using statement instead.
// This try-finally statement only calls Dispose in the finally block. Font font1 = new Font("Arial", 10.0f); try { byte charset = ; } 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 = ; }
&& and || operators
To avoid exceptions and improve performance by skipping the necessary comparisons, use && instead of & when performing the comparisons, and || instead of | as shown in the following example.
("Enter a dividend: "); var dividend = Convert.ToInt32(()); ("Enter a divisor: "); var divisor = Convert.ToInt32(()); // 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)) { ("Quotient: {0}", dividend / divisor); } else { ("Attempted division by 0 ends up here."); }
New operator
When typed implicitly, use the concise form of object instantiation, as shown in the following statement.
var instance1 = new ExampleClass();
The previous line is equivalent to the declaration below.
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(); = "Desktop"; = 37414; = "Redmond"; = 2.3;
Event handling
If you are defining an event handler that does not need to be deleted later, use the lambda expression.
public Form2() { // You can use a lambda expression to define an event handler. += (s, e) => { ( ((MouseEventArgs)e).()); }; } // Using a lambda expression shortens the following traditional definition. public Form1() { += new EventHandler(Form1_Click); } void Form1_Click(object sender, EventArgs e) { (((MouseEventArgs)e).()); }
Static members
Calling static members by using class name:. This approach makes the code easier to read by explicit static access. Do not use the name of the derived class to qualify static members defined in the base class. When compiling the code, the code readability is misleading, and if you add static members with the same name to the derived class, the code can be broken.
LINQ Query
Use a meaningful name for the query variable. The following example is a SeattleCustomers customer using SeattleCustomers.
var seattleCustomers = from cust in customers where == "Seattle" select ;
Use alias to ensure that the attribute names of anonymous types are capitalized in Pascal case format.
var localDistributors = from customer in customers join distributor in distributors on equals select new { Customer = customer, Distributor = distributor };
If the attribute names in the result are ambiguous, rename the attribute. For example, if your query returns the customer name and the distributor ID instead of leaving them as Name and ID in the result, rename them to explicitly that Name is the customer's name and ID is the distributor's ID.
var localDistributors2 = from cust in customers join dist in distributors on equals select new { CustomerName = , DistributorID = };
Use implicit type in declarations of query variables and scope variables.
var seattleCustomers = from cust in customers where == "Seattle" select ;
Align the query clause under the from clause, as shown in the above example.
Use the where clause before other query clauses to ensure that the subsequent query clauses act on reduced and filtered datasets.
var seattleCustomers2 = from cust in customers where == "Seattle" orderby select cust;
Use a multi-line from clause instead of the join clause to access the internal collection. For example, a collection of Student objects might contain a collection of test scores. When the following query is executed, it returns a score above 90 and returns the last name of the student who got that score.
// Use a compound from to access the inner sequence within each element. var scoreQuery = from student in students from score in where score > 90 select new { Last = , score };