|
|
|
@@ -0,0 +1,332 @@ |
|
|
|
Best practices |
|
|
|
C# Coding Conventions v.1.2 |
|
|
|
Diligent Technologies |
|
|
|
Best practices- C# Coding Conventions v.1.2 |
|
|
|
Last Updated: 5/12/2022 11:15 AM |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Table of Contents |
|
|
|
Revision History 3 |
|
|
|
Naming conventions 4 |
|
|
|
Pascal case 5 |
|
|
|
Camel case 7 |
|
|
|
Additional naming conventions 8 |
|
|
|
Layout conventions 9 |
|
|
|
Commenting conventions 10 |
|
|
|
XML Comments 11 |
|
|
|
Language guidelines 14 |
|
|
|
IF statements 15 |
|
|
|
String data type 16 |
|
|
|
Implicitly typed local variables 17 |
|
|
|
Unsigned data types 19 |
|
|
|
Arrays .....................................................................................................................................................................................20 |
|
|
|
Delegates 21 |
|
|
|
Try-catch and using statements in exception handling 23 |
|
|
|
&& and || operators 25 |
|
|
|
new operator 26 |
|
|
|
Event Handling 27 |
|
|
|
Static members 28 |
|
|
|
LINQ queries 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision History |
|
|
|
|
|
|
|
Date |
|
|
|
Release |
|
|
|
Author |
|
|
|
Description |
|
|
|
March 6[th] 2022 |
|
|
|
v.1.0 |
|
|
|
Mladen Mladenovic |
|
|
|
Initial Draft |
|
|
|
March 24[th] 2022 |
|
|
|
v.1.1 |
|
|
|
Mladen Mladenovic |
|
|
|
- Added section for usage of user-filtered exception handlers in Try-catch and using statements in exception handling |
|
|
|
- Added section for XML Comments in Commenting convetions |
|
|
|
- Deleted Security section |
|
|
|
- Added examples for left outer join in LINQ queries |
|
|
|
- Added section IF statements |
|
|
|
May 12[th] 2022 |
|
|
|
v.1.2 |
|
|
|
Mladen Mladenovic |
|
|
|
- Minor document changes |
|
|
|
- Resolved issues from comments |
|
|
|
|
|
|
|
|
|
|
|
Naming conventions |
|
|
|
|
|
|
|
There are several naming conventions to consider when writing C# code. |
|
|
|
|
|
|
|
In the following examples, any of the guidance pertaining to elements marked public is also applicable when working with protected and protected internal elements, all of which are intended to be visible to external callers. |
|
|
|
|
|
|
|
Pascal case |
|
|
|
|
|
|
|
Use pascal casing ("PascalCasing") when naming a class, record, or struct. |
|
|
|
|
|
|
|
|
|
|
|
When naming an interface, use pascal casing in addition to prefixing the name with an I. This clearly indicates to consumers that it's an interface. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When naming public members of types, such as fields, properties, events, methods, and local functions, use pascal casing. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When writing positional records, use pascal casing for parameters as they're the public properties of the record. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Camel case |
|
|
|
|
|
|
|
Use camel casing ("camelCasing") when naming private or internal fields, and prefix them with _. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When working with static fields that are private or internal, use the s_ prefix and for thread static use t_. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When writing method parameters, use camel casing. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Additional naming conventions |
|
|
|
|
|
|
|
Examples that don't include using directives [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive], use namespace qualifications. If you know that a namespace is imported by default in a project, you don't 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. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You don't have to change the names of objects that were created by using the Visual Studio designer tools to make them fit other guidelines. |
|
|
|
Layout conventions |
|
|
|
|
|
|
|
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 [HYPERLINK: https://docs.microsoft.com/en-us/visualstudio/ide/reference/options-text-editor-csharp-formatting?view=vs-2022]. |
|
|
|
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. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Commenting conventions |
|
|
|
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. |
|
|
|
Always delete unnecessary comments. |
|
|
|
If you want to make reminder comment start comment with "// TODO: ". |
|
|
|
If you want to make a note start comment with "// NOTE: ". |
|
|
|
If you want to point out a hack start comment with "// HACK: ". |
|
|
|
If you want to point out something important start comment with "// IMPORTANT: ". |
|
|
|
Don't create formatted blocks of asterisks around comments. |
|
|
|
Ensure all public members have the necessary XML comments [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/] providing appropriate descriptions about their behavior. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XML Comments |
|
|
|
|
|
|
|
C# documentation comments use XML elements to define the structure of the output documentation. One consequence of this feature is that you can add any valid XML in your documentation comments. The C# compiler copies these elements into the output XML file. While you can use any valid XML in your comments (including any valid HTML element), documenting code is recommended for many reasons. |
|
|
|
What follows are some recommendations, general use case scenarios, and things that you should know when using XML documentation tags in your C# code. While you can put any tags into your documentation comments, this article describes the recommended tags for the most common language constructs. In all cases, you should adhere to these recommendations: |
|
|
|
For the sake of consistency, all publicly visible types and their public members should be documented. |
|
|
|
Private members can also be documented using XML comments. However, it exposes the inner (potentially confidential) workings of your library. |
|
|
|
At a bare minimum, types and their members should have a <summary> tag because its content is needed for IntelliSense. |
|
|
|
Documentation text should be written using complete sentences ending with full stops. |
|
|
|
Partial classes are fully supported, and documentation information will be concatenated into a single entry for each type. |
|
|
|
XML documentation starts with ///. When you create a new project, the templates put some starter /// lines in for you. The processing of these comments has some restrictions: |
|
|
|
The documentation must be well-formed XML. If the XML isn't well formed, the compiler generates a warning. The documentation file will contain a comment that says that an error was encountered. |
|
|
|
Some of the recommended tags have special meanings: |
|
|
|
The <param> tag is used to describe parameters. If used, the compiler verifies that the parameter exists and that all parameters are described in the documentation. If the verification fails, the compiler issues a warning. |
|
|
|
The cref attribute can be attached to any tag to reference a code element. The compiler verifies that this code element exists. If the verification fails, the compiler issues a warning. The compiler respects any using statements when it looks for a type described in the cref attribute. |
|
|
|
The <summary> tag is used by IntelliSense inside Visual Studio to display additional information about a type or member. |
|
|
|
Developers are free to create their own set of tags. The compiler will copy these to the output file. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Some of the recommended tags can be used on any language element. Others have more specialized usage. Finally, some of the tags are used to format text in your documentation. This article describes the recommended tags organized by their use. |
|
|
|
The compiler verifies the syntax of the elements followed by a single * in the following list. Visual Studio provides IntelliSense for the tags verified by the compiler and all tags followed by ** in the following list. In addition to the tags listed here, the compiler and Visual Studio validate the <b>, <i>, <u>, <br/>, and <a> tags. The compiler also validates <tt>, which is deprecated HTML. |
|
|
|
General Tags [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] used for multiple elements - These tags are the minimum set for any API. |
|
|
|
<summary> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags]: The value of this element is displayed in IntelliSense in Visual Studio. |
|
|
|
<remarks> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] ** |
|
|
|
Tags used for members [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] - These tags are used when documenting methods and properties. |
|
|
|
<returns> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags]: The value of this element is displayed in IntelliSense in Visual Studio. |
|
|
|
<param> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] *: The value of this element is displayed in IntelliSense in Visual Studio. |
|
|
|
<paramref> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<exception> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] * |
|
|
|
<value> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags]: The value of this element is displayed in IntelliSense in Visual Studio. |
|
|
|
Format documentation output [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] - These tags provide formatting directions for tools that generate documentation. |
|
|
|
<para> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<list> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<c> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<code> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<example> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] ** |
|
|
|
Reuse documentation text [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] - These tags provide tools that make it easier to reuse XML comments. |
|
|
|
<inheritdoc> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] ** |
|
|
|
<include> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] * |
|
|
|
Generate links and references [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] - These tags generate links to other documentation. |
|
|
|
<see> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] * |
|
|
|
<seealso> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] * |
|
|
|
<cref> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
<href> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
Tags for generic types and methods [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] - These tags are used only on generic types and methods |
|
|
|
<typeparam> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] *: The value of this element is displayed in IntelliSense in Visual Studio. |
|
|
|
<typeparamref> [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/recommended-tags] |
|
|
|
|
|
|
|
NOTE: For more information and examples how to use XML comments and generate documentation with recommended tools please visit a link [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/]. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Language guidelines |
|
|
|
|
|
|
|
The following sections describe practices that the C# team follows to prepare code examples and samples. |
|
|
|
|
|
|
|
IF statements |
|
|
|
|
|
|
|
When writing IF statements always use curly brackets for statements, even if statement is one line of code. |
|
|
|
|
|
|
|
String data type |
|
|
|
|
|
|
|
Use string interpolation [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated] to concatenate short strings, as shown in the following code. |
|
|
|
|
|
|
|
|
|
|
|
To append strings in loops, especially when you're working with large amounts of text, use a StringBuilder [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/api/system.text.stringbuilder] object. |
|
|
|
|
|
|
|
|
|
|
|
Implicitly typed local variables |
|
|
|
|
|
|
|
Use implicit typing [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables] 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. |
|
|
|
|
|
|
|
|
|
|
|
Don't use var [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var] when the type is not apparent from the right side of the assignment. Don't assume the type is clear from a method name. A variable type is considered clear if it's a new operator or an explicit cast. |
|
|
|
|
|
|
|
Don't rely on the variable name to specify the type of the variable. It might not be correct. In the following example, the variable name inputInt is misleading. It's a string. |
|
|
|
|
|
|
|
Avoid the use of var in place of dynamic [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/reference-types]. Use dynamic when you want run-time type inference. For more information, see Using type dynamic (C# Programming Guide) [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic]. |
|
|
|
Use implicit typing to determine the type of the loop variable in for [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements] loops. The following example uses implicit typing in a for statement. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Don't use implicit typing to determine the type of the loop variable in foreach [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements] loops. |
|
|
|
|
|
|
|
The following example uses explicit typing in a foreach statement. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Unsigned data types |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
Arrays |
|
|
|
|
|
|
|
Use the concise syntax when you initialize arrays on the declaration line. In the following example, note that you can't use var instead of string[]. |
|
|
|
|
|
|
|
If you use explicit instantiation, you can use var. |
|
|
|
|
|
|
|
If you specify an array size, you have to initialize the elements one at a time. |
|
|
|
|
|
|
|
|
|
|
|
Delegates |
|
|
|
|
|
|
|
Use Func<> and Action<> instead of defining delegate types. In a class, define the delegate method. |
|
|
|
|
|
|
|
Call the method using the signature defined by the Func<> or Action<> delegate. |
|
|
|
|
|
|
|
If you create instances of a delegate type, use the concise syntax. In a class, define the delegate type and a method that has a matching signature. |
|
|
|
|
|
|
|
Create an instance of the delegate type and call it. The following declaration shows the condensed syntax. |
|
|
|
|
|
|
|
|
|
|
|
The following declaration uses the full syntax. |
|
|
|
|
|
|
|
|
|
|
|
Try-catch and using statements in exception handling |
|
|
|
|
|
|
|
Use a try-catch [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch] statement for most exception handling. |
|
|
|
|
|
|
|
Simplify your code by using the C# using statement [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement]. If you have a try-finally [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally] statement in which the only code in the finally block is a call to the Dispose [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose] method, use a using statement instead. |
|
|
|
In the following example, the try-finally statement only calls Dispose in the finally block. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You can do the same thing with a using statement. |
|
|
|
|
|
|
|
In C# 8 and later versions, use the new using syntax [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement] that doesn't require braces: |
|
|
|
|
|
|
|
User-filtered exception handlers catch and handle exceptions based on requirements you define for the exception. These handlers use the catch statement with the when keyword. |
|
|
|
This technique is useful when a particular exception object corresponds to multiple errors. In this case, the object typically has a property that contains the specific error code associated with the error. You can use the error code property in the expression to select only the particular error you want to handle in that catch clause. |
|
|
|
The following example illustrates the catch/when statement. |
|
|
|
|
|
|
|
|
|
|
|
&& and || operators |
|
|
|
|
|
|
|
To avoid exceptions and increase performance by skipping unnecessary comparisons, use && [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators] instead of & [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators] and || [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators] instead of | [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators] when you perform comparisons, as shown in the following example. |
|
|
|
|
|
|
|
If the divisor is 0, the second clause in the if statement would cause a run-time error. But the && operator short-circuits when the first expression is false. That is, it doesn't evaluate the second expression. The & operator would evaluate both, resulting in a run-time error when divisor is 0. |
|
|
|
|
|
|
|
new operator |
|
|
|
|
|
|
|
Use one of the concise forms of object instantiation, as shown in the following declarations. The second example shows syntax that is available starting in C# 9. |
|
|
|
|
|
|
|
The preceding declarations are equivalent to the following declaration. |
|
|
|
|
|
|
|
Use object initializers to simplify object creation, as shown in the following example. |
|
|
|
|
|
|
|
The following example sets the same properties as the preceding example but doesn't use initializers. |
|
|
|
|
|
|
|
|
|
|
|
Event Handling |
|
|
|
|
|
|
|
If you're defining an event handler that you don't need to remove later, use a lambda expression. |
|
|
|
|
|
|
|
The lambda expression shortens the following traditional definition. |
|
|
|
|
|
|
|
|
|
|
|
Static members |
|
|
|
|
|
|
|
Call static [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static] members by using the class name: ClassName.StaticMember. This practice makes code more readable by making static access clear. Don't 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. |
|
|
|
|
|
|
|
LINQ queries |
|
|
|
|
|
|
|
Use meaningful names for query variables. The following example uses seattleCustomers for customers who are located in Seattle. |
|
|
|
|
|
|
|
Use aliases to make sure that property names of anonymous types are correctly capitalized, using Pascal casing. |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
Use implicit typing in the declaration of query variables and range variables. |
|
|
|
|
|
|
|
Align query clauses under the from [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/from-clause] clause, as shown in the previous examples. |
|
|
|
|
|
|
|
|
|
|
|
Use where [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-clause] clauses before other query clauses to ensure that later query clauses operate on the reduced, filtered set of data. |
|
|
|
|
|
|
|
Use multiple from clauses instead of a join [HYPERLINK: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/join-clause] 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. |
|
|
|
|
|
|
|
Perform left outer joins with clause. |
|
|
|
|
|
|
|
|