Coding Guidelines for C#
Table of Contents
2.3 Namespace Naming Guidelines 5
2.5 Interface Naming Guidelines 6
2.6 Parameter Naming Guidelines 7
2.7 Method Naming Guidelines 7
2.8 Property Naming Guidelines 8
2.10 Constants Naming Guidelines 9
2.11 Enumeration Naming Guidelines 9
2.12 Static field Naming Guidelines 9
2.13 Attribute Naming Guidelines 10
2.15 Code Commenting Conventions 11
3.0 Class Member Usage Guidelines 12
3.1 Property Usage Guidelines 12
3.3 Method Usage Guidelines 13
3.4 Constructor Usage Guidelines 14
3.6 Parameter Usage Guidelines 15
4.1 Base Class Usage Guidelines 16
4.2 Inheritance Usage Guidelines 16
6.2 Method / Function Header 17
1.0 Introduction
The readability of source code has a direct impact on how well a developer comprehends a software system. Code maintainability refers to how easily the software system can be changed to add new features, modify existing features, fix bugs, or improve performance. Although readability and maintainability are the result of many factors, one particular facet of software development upon which all developers have an influence is coding technique. The easiest method to ensure that a team of developers will produce quality code is to establish a coding standard, which is then enforced by routine code reviews or by using the advance template features of VS.NET by which the guidelines and best practices may be enforced.
1.1 Purpose
This document is a compendium of programming practices and techniques that are to be followed while programming in C#. The documented set is guidelines expected at making the program more structured, readable, maintainable. This also provides guidelines to enhance the application performance.
1.2 Scope
This document defines a broad set of guidelines to adhere to while creating application in C#. This document only lists down a set of guidelines in the broad sense.
1.3 Intended Audience
This document is meant for a technical audience with knowledge and familiarity with Microsoft .Net Framework.
2.0 Naming Conventions
Before going through the rules for naming program elements, be aware of the most common ways of using character casing to distinguish between elements. They are:
Pascal casing: The first character is upper case, and the first letter of each word is also upper case. All other characters are lower case;
For example, Current Temperature
Camel casing: The first character is not upper case, but the first letter of each word is upper case. All other characters are lower case;
For example, current Temperature
UpperCase: All letters in the identifier are capitalized. Use this convention only for identifiers that consist of two or fewer letters.
For example, System.Web.UI
MixedCase: Both Upper case and Lower case letters can be used. First word can be in upper case and second in lower case
For example, PosSystem
2.1 Case Sensitivity
Do not use names that depend on the case-sensitive features of the language. Components must be fully usable from both case-sensitive and case-insensitive languages. Case-insensitive languages cannot distinguish between two names within the same context that differ only by case. Therefore, avoid this situation in the components or classes that are created.
Do not create two namespaces with names that differ only by case. For example, a case insensitive language cannot distinguish between the following two namespace declarations.
ý
namespace cognizant.applicationblocks;
namespace Cognizant.ApplicationBlocks;
Do not create a function with parameter names that differ only by case.
ý
void GetEmpDetails (string empName, string EmpName)
Do not create a type with method names that differ only by case. In the following example, calculate and Calculate are inappropriate method names because they differ only by case.
ý
void calculate()
void Calculate()
2.2 Abbreviations
Do not use abbreviations or contractions as parts of identifier names.
þ
GetName is more meaningful compared to GetNm
Do not use acronyms that are not generally used in the IT or Retail field. Where appropriate, use well-known acronyms to replace lengthy phrase names.
þ
Use UI for User Interface.
Do not use class names that duplicate commonly used .NET Framework namespaces.
ý
System, Collections, Forms, or UI
2.3 Namespace Naming Guidelines
· Prefixing namespace names with a company name or other well-established brand avoids the possibility of two published namespaces having the same name. For example, Microsoft.Office is an appropriate prefix for the Office Automation Classes provided by Microsoft.
· Use Pascal case for namespaces, and separate logical components with periods
· Use plural namespace names if it is semantically appropriate. For example, use System.Collections rather than System.Collection. Exceptions to this rule are brand names and abbreviations. For example, use System.IO rather than System.IOs.
· Do not use the same name for a namespace and a class. For example, try not to provide both Debug namespace and Debug class.
· Do not use characters like “_”, #, $.
2.4 Class Naming Guidelines
The following rules outline the guidelines for naming classes:
· Use a noun or noun phrase to name a class.
· Use Pascal case.
· Use abbreviations sparingly.
· Do not use a type prefix, such as C for class, on a class name. For example, use the class name FileStream rather than CFileStream.
· Do not use the underscore character (_).
· Occasionally, it is necessary to provide a class name that begins with the letter I, even though the class is not an interface. This is appropriate as long as I is the first letter of an entire word that is a part of the class name. For example, the class name IdentityStore is appropriate.
· Where appropriate, use a compound word to name a derived class. The second part of the derived class’s name should be the name of the base class. For example, ApplicationException is an appropriate name for a class derived from a class named Exception, because ApplicationException is a kind of Exception. Use reasonable judgment in applying this rule. For example, Button is an appropriate name for a class derived from Control. Although a button is a kind of control, making Control a part of the class name would lengthen the name unnecessarily.
· Avoid using class names that duplicate commonly used .NET Framework namespaces. For example, do not use any of the following names as a class name: System, Collections, Forms, or UI. See the Class Library for a list of .NET Framework namespaces
þ
public class Inventory
public class Parts
ý
public class clsInventory ( has cls as prefix )
public class cls_Inventory ( class name with underscore )
2.5 Interface Naming Guidelines
The following rules outline the naming guidelines for interfaces:
· Prefix interface names with the letter I, to indicate that the type is an interface.
· Name interfaces with nouns or noun phrases, or adjectives that describe behavior. For example, the interface name IComponent uses a descriptive noun. The interface name ICustomAttributeProvider uses a noun phrase. The name IPersistable uses an adjective.
· Use Pascal case.
· Use abbreviations sparingly.
· Use similar names when a class/interface pair is defined, where the class is a standard implementation of the interface. The names should differ only by the letter I prefix on the interface name.
· Do not use the underscore character (_).
þ
public interface IServiceProvider
public interface IFormatable
ý
public interface Serviceprovider ( Pascal case not used here)
public interface ServiceProvider ( Interface name not prefixed with an “I” )
public interface IService_Provider ( This interface name has an “_” within the name )
2.6 Parameter Naming Guidelines
· Use descriptive parameter names. Parameter names should be descriptive enough that the name of the parameter and its type can be used to determine its meaning in most scenarios.
· Use camel case for parameter names.
· Use names that describe a parameter's meaning rather than names that describe a parameter's type.
· Do not prefix parameter names with Hungarian type notation.
þ
Type GetType(string typeName)
string Format (string format, object[] args)
string ReadModels(int businessUnit , int makeId)
ý
string ReadModels(int BusinessUnit, int MakeId)( Camel case not used to define parameter names )
string Format( string _format) ( “_” used as prefix which is wrong )
2.7 Method Naming Guidelines
The following rules outline the naming guidelines for methods:
· Use verbs or verb phrases to name methods.
· Use Pascal case.
· Avoid using underscores (“_”) in method names.
þ
ReadModels()
KillAllSessions()
ý
AllSessions() (action as to what this method does is not clearly specified)
readModels() ( Pascal case not used here )
Read_Names() (Under score “_” used here)
2.8 Property Naming Guidelines
The following rules outline the naming guidelines for properties:
· Use a noun or noun phrase to name properties.
· Use Pascal case.
· Do not use Hungarian notation.
þ
public class SampleClass
{
public long AverageTemperature
{
// Code for Get and Set accessors goes here.
}
}
ý
public class SampleClass
{
public long GetTemperature
{
// Code for Get and Set accessors goes here.
}
}
This example names the property as Temperature, which is not clear whether it means body temperature or it means Average Temperature.
2.9 Event Naming Guidelines
The following rules outline the naming guidelines for events:
· Use Pascal case.
· Do not use Hungarian notation.
· Use an EventHandler suffix on event handler names.
· Specify two parameters named sender and e. The sender parameter represents the object that raised the event. The sender parameter is always of type object, even if it is possible to use a more specific type. The state associated with the event is encapsulated in an instance of an event class named e. Use an appropriate and specific event class for the e parameter type.
· Name an event argument class with the EventArgs suffix.
þ
public delegate void MouseEventHandler( object sender, MuseEventArgs e);
ý
public delegate void Mouse (object sender, EventArgs e);
2.10 Constants Naming Guidelines
Constants should be named in all capitals and multiple words concatenated with ‘_’ character
þ
public const MAX_VALUE = 500;
public const MIN_VALUE = 200 ;
ý
public const MAXVALUE = 500; ( not concatenated with “_” )
2.11 Enumeration Naming Guidelines
The following rules outline the naming guidelines for enumerations:
· Use Pascal case for Enum types and value names.
· Use abbreviations sparingly.
· Do not use an Enum suffix on Enum type names.
· Use a singular name for most Enum types, but use a plural name for Enum types that are bit fields.
· Always add the FlagsAttribute to a bit field Enum type.
þ
Enum Days
Saturday
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
End Enum
ý
Enum days
SUNDAY
monday
tuesday
wednesday
ThursDay
FRiday
Saturday
End Enum
2.12 Static field Naming Guidelines
The following rules outline the naming guidelines for static fields:
· Use nouns, noun phrases, or abbreviations of nouns to name static fields.
· Use Pascal case.
· Do not use a Hungarian notation prefix on static field names.
· It is recommended that you use static properties instead of public static fields whenever possible.
þ
public static readonly Color White = new Color(0xFFFFFF);
ý
public static readonly Color colwhite = new Color(0xFFFFFF);
2.13 Attribute Naming Guidelines
The following rules outline the naming guidelines for static fields:
· Use Pascal case.
· Always add suffix “Attribute” to custom attribute classes.
þ
public class RequiresTransactionAttribute
ý
public class requiresTransaction
2.14 Capitalization Styles
The following table summarizes the capitalization rules and provides examples for the different types of identifiers.
Identifier | Case | Example |
Class | Pascal | AppDomain |
Enum type | Pascal | ErrorLevel |
Enum values | Pascal | FatalError |
Event | Pascal | ValueChange |
Exception class | Pascal | WebException Note Always ends with the suffix Exception. |
Read-only Static field | Pascal | RedValue |
Interface | Pascal | IDisposable Note Always begins with the prefix |
Method | Pascal | ToString |
Namespace | Pascal | System.Drawing |
Parameter | Camel | employeeId |
Property | Pascal | BackColor |
Protected instance field | Camel | redValue Note Rarely used. A property is preferable to using a protected instance field. |
Public instance field | Pascal | RedValue Note Rarely used. A property is preferable to using a public instance field. |
Local variables | Camel | lastName , averageSalary , total |
Private variables | Camel | country, flightNumber |
2.15 Code Commenting Conventions
Comments should be included in source code to indicate what the code does and to break up large sections of code.
· Comments lines should begin with // indented at the same level as the code they are documenting.
· Do not use /* ... */ blocks for comments.
· Indent comments at the same level of indentation as the code
· Source code comments should be written in clear, concise, and English with correct spelling and grammar.
· Never "comment out" code without including a description of the reason for doing so. If the code isn't necessary, it should be deleted
· Do not use "clutter" comments, such as an entire line of asterisks. Instead, use a single blank line white space line to separate comments from code.
þ
long estimatedCost = 0 ; // this variable holds the estimated cost
þ
//
// this block of the code will
// perform the calculations required.
//
Note: There should be a blank line before the multi line comment starts and also after it ends. .NET IDE auto commenting feature can be used to comment the entire block.
· Comments should explain, why the particular code is there and not how it is being done
ý
// Check if customer object is null
if(customer != null)
{
……;
}
þ
// Check the customer for validity before saving data
if(customer != null)
{
……;
}
3.0 Class Member Usage Guidelines
· Use Pascal Casing for Property Names
· Do not use Hungarian Notation.
3.1 Property Usage Guidelines
· Use a property when the member is a logical data member.
Below, Name is a property because it is a logical member of the class.
þ
public string Name
{
get
{
return modelName;
}
set
{
modelName = value;
}
}
3.2 Event Usage Guidelines
· When the events in documentation are referred, use the phrase, "an event was raised" instead of "an event was fired" or "an event was triggered."
· Use return type of void for event handlers, as shown in the following example
þ
public delegate void MouseEventHandler (object sender, MouseEventArgs e);
· Implement an event handler using the public EventHandler Click syntax. Provide an add and a remove accessor to add and remove event handlers.
· Use a protected virtual method to raise each event.
· Classes should be ready for the event handler to perform almost any operation, and in all cases the object should be left in an appropriate state after the event has been raised. Consider using a try/finally block at the point in code where the event is raised. Since the developer can call back on the object to perform other actions, do not assume anything about the object state when control returns to the point at which the event was raised.
3.3 Method Usage Guidelines
· By default, methods are non virtual. Maintain this default in situations where it is not necessary to provide virtual methods.
· Use method overloading to provide different methods that do semantically the same thing.
· Use method overloading instead of allowing default arguments. Default arguments do not version well.
þ
int String.IndexOf (string name);
int String.IndexOf (string name, int startIndex);
· Use default values correctly. In a family of overloaded methods, the complex method should use parameter names that indicate a change from the default state assumed in the simple method. For example, in the following code, the first method assumes the search will not be case-sensitive. The second method uses the name ignoreCase rather than caseSensitive to indicate how the default behaviour is being changed.
þ
// Method #1: bool ignoreCase = false.
MethodInfo Type.GetMethod(string employeeName);
// Method #2: Indicates how the default behavior of method #1 is being changed.
MethodInfo Type.GetMethod (string employeeName, bool ignoreCase);
· Use a consistent ordering and naming pattern for method parameters. It is common to provide a set of overloaded methods with an increasing number of parameters to allow the developer to specify a desired level of information.
ý
public int GetDueAmount(int empId, string empDepartment, string empFirstName, string empLastName)
public int GetDueAmount(int empId, string empFirstNm , string empDepartment)
public int GetDueAmount(string empDepartment , int empId)
þ
public int GetDueAmount(int empId, string empDepartment, string empFirstName, string empLastName)
public int GetDueAmount(int empId, string empDepartment, string empFirstName )
public int GetDueAmount(int empId ,string empDepartment)
· If the ability to override a method must be provided, make only the most complete overload virtual and define the other operations in terms of it.
· The Return statement should not be used in conjunction with other processing
ý
- Return (principleAmount+interestDue)*inflationRate
or
- Return interest.Calculate(interestRate, principleAmount)
þ
int netDueAmount = (principleAmount+interestDue)*inflationRate;
return netDueAmount;
or
int netDueAmount = interest.Calculate(interestRate, principleAmount);
return netDueAmount;
· Use proper flower brace styles for C# methods for readability
þ
public void GetDetails()
{
//code
}
3.4 Constructor Usage Guidelines
· Provide a default private constructor if there are only static methods and properties on a class. The private constructor prevents the class from being created.
þ
public sealed class Environment
{
// Private constructor prevents the class from being created.
private Environment()
{
// Code for the constructor goes here.
}
}
· Minimize the amount of work done in the constructor. Constructors should not do more than capture the constructor parameter or parameters.
· Provide a protected constructor that can be used by types in a derived class.
· Use parameters in constructors as shortcuts for setting properties. There should be no difference in semantics between using an empty constructor followed by property set accessors, and using a constructor with multiple arguments.
þ
Use
Traveler traveler = new Traveler ("Mark", "PHL");
Instead of
Traveler traveler = new Traveler ();
traveler.Name = "Mark";
traveler.Location = "PHL";
· Use a consistent ordering and naming pattern for constructor parameters.
3.5 Field Usage Guidelines
· Do not use instance fields that are public or protected. If exposing of fields directly to the developer is avoided, classes can be versioned more easily because a field cannot be changed to a property while maintaining binary compatibility. Consider providing get and set property accessors for fields instead of making them public. The presence of executable code in get and set property accessors allows later improvements, such as creation of an object on demand, upon usage of the property, or upon a property change notification.
· Expose a field to a derived class by using a protected property that returns the value of the field.
þ
public class Control: Component
{
private int controlHandle;
protected int Handle
{
get
{
return controlHandle;
}
}
}
· It is recommended to use read-only static fields instead of properties where the value is a global constant.
þ
public struct Int32
{
public static readonly int MaxValue = 2147483647;
public static readonly int MinValue = -2147483648;
// Insert other members here.
}
· Spell out all words used in a field name. Do not use uppercase letters for field names.
· Do not apply a prefix to field names or static field names. Specifically, do not apply a prefix to a field name to distinguish between static and nonstatic fields.
ý
Applying a g_ or s_ prefix is incorrect.
· Use public static read-only fields for predefined object instances. If there are predefined instances of an object, declare them as public static read-only fields of the object itself. Use Pascal case because the fields are public.
3.6 Parameter Usage Guidelines
· Check for valid parameter arguments. Perform argument validation for every public or protected method and property set accessor. Throw meaningful exceptions to the developer for invalid parameter arguments.
· The actual checking does not necessarily have to happen in the public or protected method itself. It could happen at a lower level in private routines. The main point is that the entire surface area that is exposed to the developer checks for valid arguments.
4.0 Type Usage Guidelines
4.1 Base Class Usage Guidelines
· From a versioning perspective, classes are more flexible than interfaces.
· Provide class customization through protected methods.
· Many compilers will insert a public or protected constructor if one does not. Therefore, for better documentation and readability of source code, explicitly define a protected constructor on all abstract classes.
· Use sealed classes if it will not be necessary to create derived classes. A class cannot be derived from a sealed class.
· Use sealed classes if there are only static methods and properties on a class.
4.2 Inheritance Usage Guidelines
· Examine objects for parent-child relationships to identify possible superclasses from which to derive the subclasses.
· Look for multiple levels of parent-child relationships to build and Inheritance Tree.
· Override attributes in the derived class when the inherited functionality does not fit the needs. (If overriding most of the inherited functions, then this probably is not a good candidate for inheritance.)
· When modeling, decide which superclass functions can be overridden and which must be overridden, and declare these as Overridable or Must Override
5.0 Generic Guidelines
· The code should resemble with the design doc. Programmer should not implement a different logic to carry out the same activity.
· All the class variables should be declared as private.
· Any Public variable required should be declared as a class property rather than Public.
· Do not use destructor of the class to carry out cleanup activity, if this is required, implement IDisposable interface and provide Dispose method. The dispose should also suppress Finalisation by calling “gc.suppressfinalization” method. Every usage of dispose() should have appropriate comments justifying it’s use.
· If the type being used overrides dispose(), the method overriding dispose() should be explicitly called.
· Transaction.Supported Attributes should not set on Select operation
· The versioning info for the components should be set in AssemblyInfo file.
· The Isolation levels should be set correctly for serviced components.
· Wherever lots of parameters has to be passed to the methods for operations respective DataEntities should be used
· Use of unsafe code should be avoided.
· Variables should be declared as late as possible.
· When there is a requirement for lots of string manipulation and the number of manipulations is not known, use StringBuilder object. See the example below:
ý
string delimtedData = “”;
for(dataIndex = 0; dataIndex < dataCount; ++ dataIndex)
{
delimtedData = delimtedData + customerData[dataIndex] + “||”;
}
þ
StringBuilder delimtedData = new StringBuilder("", dataCount);
for(dataIndex = 0; dataIndex < dataCount; ++ dataIndex)
{
delimtedData.Append(customerData[dataIndex]);
delimtedData.Append(“||”);
}
· Application should use P/Invoke when there is a requirement to call into un-managed code from managed code.
· The dispose() method for the Serviced components must be called from the clients.
· Code generated from Visual Studio.NET IDE should be left as it is. It should NOT be modified.
6.0 Headers
6.1 Class / File Header
· Every class file should have a header, providing the below listed information about the class file.
· The below information can be enclosed within #region…..#end region directive to make the header collapsible.
þ
#region File Header
//
// File : FileName.cs
// Project :
// Description :
// This method Reads the model list
// Change History :
// Date Version Author Remarks
// dd-mm-yyyy VerNumber Author Name Version(1.0)
//
#end region
6.2 Method / Function Header
In Visual C# code can be documented using XML. C# is the only programming language in Visual Studio .NET with this feature.
· Every method / function in a class should be commented using XML documentation
· For more details about XML commenting , refer the following URL from Microsoft
þ
/// <summary>
/// This method Reads the employee details.
/// Populates the employee list.
/// </summary>
/// <param name="empId">Respective Employee Id</param>
public void ReadEmployeeDetails(int empId)
{
//Implementation goes here
}
7.0 Format–Indenting
Indent all statements inside classes, methods, loops, if statements, switch statements, try/catch blocks, etc. Statements should be indented in four-space increments (4, 8, 12, 16, 20, etc.).
VS. Net’s feature to set the tab spaces to multiples of 4 automatically can be used.
þ
private bool InZone()
{
// declarations
foreach (expression)
{
if (expression) // Only check if the zone isn't the current one.
{
// code goes here
}
}
return false;
}
8.0 Format–Brace Alignment
Align open and close braces vertically where brace pairs align and should be placed on a line by themselves.
þ
for (purchaseItemIndex = 0; purchaseItemIndex < totalPurchases; purchaseItemIndex ++)
{
if (totalPurchaseAmount < 0)
{
...
}
}
ý
for (purchaseItemIndex = 0; purchaseItemIndex < 100; purchaseItemIndex++) {
if (totalPurchaseAmount < 0) {
...
}
}
Always use a curly brace scope in an if statement, even if a true condition executes a single statement.
þ
if (itemFound == true)
{
itemCounter++;
}
ý
if (itemFound == true)
itemCounter++;
9.0 Best Practices
· Avoid using terms such as Flag when naming status variables, which differ from Boolean variables in that they may have more than two possible values. Instead of documentFlag, use a more descriptive name such as documentFormatType.
· Avoid adding comments at the end of a line of code; end-line comments make code more difficult to read. However, end-line comments are appropriate when annotating variable declarations
· Use comments to explain the intent of the code. They should not serve as inline translations of the code.
· Break large, complex sections of code into smaller, comprehensible modules. For example if number of lines of code for a particular function or method exceeds 30 lines, the code can be broken into smaller functions probably.
· Use a monospace font when publishing hard-copy versions of the source code
· Where appropriate, avoid placing more than one statement per line.
· To avoid having to scroll the source code window and to allow for a clean hard-copy presentation, establish a maximum line length for comments and code. Make sure that the code does not scroll through horizontally in the IDE.
· Make sure no variables are defined inside loops.
· Make sure variables are assigned default values.
· Operator overloading should be generally avoided unless a very compelling case exists. Implement. Equals () or .Clone () instead.
· The body of all methods should be wrapped in a try..catch block and all exceptions logged as described in Error Reporting section. Use finally appropriately where some resources need to be released before program termination.
· Collections are preferable to Arrays, and should be used unless there is a clear case for an array.
· Use the System.Convert class for all type casting.
· Try and keep all the declaration of local variables at the beginning of a block
· Divide the code into regions using #region….#end region which increases the readability.
þ
public class Employee
{
#region Constructor
public Employee ()
{
}
#endregion
#region Method: CalculateIncentive
public void CalculateIncentive(int empId)
{
//implementation goes here
}
#endregion
}
10.0 Exception Handling
· Do not throw exceptions in situations that are normal or expected (e.g. end-of-file). Use return values or status enumerations instead. In general, try to design classes that do not throw exceptions in the normal flow of control. However, do throw exceptions that a user is not allowed to catch when a situation occurs that may indicate a design error in the way your class is used or in situations like loss of db connection or error during SQL statement execution.
· Do not throw exceptions from inside destructors. When you call an exception from inside a destructor, the CLR will stop executing the destructor, and pass the exception to the base class destructor (if any). If there is no base class, then the destructor is discarded.
· Using Specific Exceptions in a Catch Block: When an exception occurs, it is passed up the stack and each catch block is given the opportunity to handle it. The order of catch statements is important. Put catch blocks targeted to specific exceptions before a general exception catch block or the compiler might issue an error. The proper catch block is determined by matching the type of the exception to the name of the exception specified in the catch block. If there is no specific catch block, the exception is caught by a general catch block, if one exists.
The following code example uses a try/catch block to catch an InvalidCastException. The sample creates a class called Employee with a single property, employee level (EmLevel). A method, PromoteEmployee, takes an object and increments the employee level. An InvalidCastException occurs when a DateTime instance is passed to the PromoteEmployee method
þ
using System;
public class Employee
{
//Create employee level property.
public int Level
{
get
{
return (employeeLevel);
}
set
{
employeeLevel = value;
}
}
int employeeLevel;
}
public class EmployeeChanges
{
public static void PromoteEmployee (Object employee)
{
//Cast object to Employee.
Employee employeeToPromote = (Employee) employee;
// Increment employee level.
employeeToPromote.Level = employeeToPromote.Level + 1;
}
public static void Main ()
{
try
{
Object employee = new Employee ();
DateTime newYear = new DateTime (2001, 1, 1);
//Promote the new employee.
PromoteEmployee (employee);
//
//Promote DateTime; results in InvalidCastException as newYear is
// not an employee instance.
//
PromoteEmployee (newYear);
}
catch (InvalidCastException e)
{
Console.WriteLine ("Error passing data to PromoteEmployee method.” + e);
}
}
}
· Allow callers to prevent exceptions by providing a method or
property that returns the object’s state: For example, consider a communication layer that will throw an InvalidOperationException when an attempt is made to call Send() when no connection is available. To allow preventing such a situation, provide a property such as Connected to allow the caller to determine if a connection is available before attempting an operation.
· Using User-Defined Exceptions:
If you want users to be able to programmatically distinguish between some error conditions, you can create your own user-defined exceptions. The .NET Framework provides a hierarchy of exception classes ultimately derived from the base class Exception. Each of these classes defines a specific exception, so in many cases you only have to catch the exception. You can also create your own exception classes by deriving from the ApplicationException class. In the following example, a new exception class, employeeNotFoundException,is derived from System.ApplicationException. Three constructors are defined in the class, each taking different parameters.
þ
using System;
public class EmployeeNotFoundException: ApplicationException
{
public EmployeeNotFoundException()
{
//Implementation goes here
}
public EmployeeNotFoundException(string message): base(message)
{
//Implementation goes here
}
public EmployeeNotFoundException(string message, Exception inner): base(message, inner)
{
//Implementation goes here
}
}
· Using the Finally Block:
When an exception occurs, execution stops and control is given to the closest exception handler. This often means that lines of code you expect to always be called are not executed. Some resource cleanup, such as closing a file, must always be executed even if an exception is thrown. To accomplish this, you can use a finally block. A finally block is always executed, regardless of whether an exception is thrown.
The following code example uses a try/catch block to catch an ArgumentOutOfRangeException. The Main method creates two arrays and attempts to copy one to the other. The action generates an ArgumentOutOfRangeException and the error is written to the console. The finally block executes regardless of the outcome of the copy action.
þ
using System;
class ArgumentOutOfRangeExample
{
static public void Main ()
{
int[] age={0,0};
int[] ageClone={0,0};
try
{
Array.Copy(age, ageClone,-1);
}
catch (ArgumentOutOfRangeException e)
{
//Logging implementation goes here
}
finally
{
//Resource cleanup implementation goes here
}
}
}
11.0 References
.NET Framework Guidelines from MSDN