Back-2-Basics: .NET Coding Standards For The Real World
Check Out Your Local User Groups!San Diego Cloud Computing User Groupwww.azureusergroup.com/group/sandiegoazureusergroupSan Diego .NET Developers Groupwww.sddotnetdg.orgSan Diego .NET User Groupwww.sandiegodotnet.comSan Diego SQL Server User Groupwww.sdsqlug.org
Win Free Software!RulesProvide your business card (or email and name)*Indicate on the back what software you are interested inOtherwise I will pick Winners will be picked next week*Yes, most likely I’m going to send you and email about my user group (sddotnetdg.org) and or web site (dotNetTips.com)PrizesCodeRush and Refactor Pro from DevExpress (4)SecondCopy (automatic backup software) (5) *CodeIt.Right Standard from SubMain (4)*Requires mailing address and phone number
Agenda5
Overview
Why Do You Need Standards?First, you might not agree witheverything I say… that’s okay!Pick a standard for your companyEvery programmer on the same pageEasier to read and understand codeEasier to maintain codeProduces more stable, reliable codeStick to the standard!!!
After Selecting a StandardMake sure it’s easily available to each programmerPrint or electronicallyEnforce via code reviewsProvide programs to make it easier for programmers to maintain:StyleCop – Free for C# programmers.CodeIt.Right – Enterprise edition shares profiles. Can create custom profiles for your company.
Real World Analysis ExampleScenario: In production Client Server Application with millions in salesNine projects of 183,177 lines of .NET code written by multiple programmers (junior to principal)StyleCopAnalyzeCode.It Right7,076< 1,1006,216< 2,5275,091< 1,837This is why you need to follow good coding practices throughout the lifecycle of the project!
Code.It Right StatsAllImportant
Assembly Layout
General Assembly TipsNever hardcode strings that might change based on deployment such as connection stringsBest place to put them are in user or application level Settings in your application.Remember to save on exit and load on start!Automatic in VB.NET Other locations can include: Registration Database, Databases and more… DEMO
General Assembly TipsSign (strong name) your assemblies, including the client applications. Also, sign interop assemblies with the project’s .snk fileName assemblies in the following format:<Company>.<Component>.dllProject names should be named the same.Microsoft.VisualBasic.dlldotNetTips.Utility.dllAcme.Services.References.dll
Mark as CLS CompliantForces your assembly to be compliant with the Common Language Specification (CLS). Assemblies, modules, and types can be CLS-compliant even if some parts of the assembly, module, or type are not CLS-compliant, as long as these two conditions are met: If the element is marked as CLS-compliant, the parts that are not CLS-compliant must be marked using CLSCompliantAttribute with its argument set to false. A comparable CLS-compliant alternative member must be supplied for each member that is not CLS-compliant.DEMO
Element Order
Elements of the Same TypeShould appear in this order:public elementsprotected elementsinternal elementsprivate elementsUse #region/ #endregion to group namespace-level and class-level elementsUse separate regions to organize the private, protected, and internal members.
NamespacesThe general rule for naming namespaces is to use the company name followed by the technology name and optionally the feature and designCompanyName.TechnologyName[.Feature][.Design]
EnumsUse abbreviations sparingly for Enums and their valuesDo not use an Enum suffix on Enum type namesUse a singular name for most Enum types, but use a plural name for Enum types that are bit fields
EnumsAlways add the FlagsAttribute to a bit field Enum typeAvoid providing explicit values for Enums (unless necessary)Avoid specifying a type for an EnumPublic Enum WebServiceAction  GetCurrentMode  PauseService  ResumeService  StartService  StopServiceEnd Enum
InterfacesPrefix interface names with the letter “I”Do not use the underscore character. Use abbreviations sparingly.Challenging to version over releasesThe smaller, more focused the interface the betterpublic interface IDisposable{    // Methods
    void Dispose();}
ClassesUse a noun or noun phrase to name a class.Avoid putting multiple classes in a single file.A file name should reflect the class it contains. Provide a default private constructor if there are only static methods and properties on a class. Use Static Class in C# or a Module in VB.NET
EventsUse Pascal caseUse an EventHandler suffix on event handler names. Name an event argument class with the EventArgs suffix.Use EventHandler<> to declare handlers.Be careful with non-UI threads calling back to the UI!Use the BackgroundWorker Control in Windows FormsDEMO
Member Variables (Fields)Use camel case as a rule, or uppercase for very small wordsPrefix private variables with a "_”Member variables should not be declared publicUse a Property insteadConst member variables may be declared public
PropertiesUse Pascal caseUse a noun or noun phrase to name propertiesProperties that return arrays or collections should be methods. Do not use write-only properties Consider providing events that are raised when certain properties are changed. Name them <Property>Changed
PropertiesProperties should not have dependencies on each otherSetting one property should not affect other propertiesProperties should be settable in any order.DEMO
ConstructorsDo not call code from a constructor!Can cause Exceptions.Capture parameters only.Provide a constructor for every class. Do not use the this./ Me. reference unless invoking another constructor from within a constructor.Provide a protected constructor that can be used by types in a derived class.
DestructorsAvoid using destructors!It is not possible to predict when garbage collection will occur.The garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams. Implement IDisposible if you do!Use the try/finally (or Using) to make sure that unmanaged resources are disposed of even if an exception interrupts your application. DEMO
MethodsUse Pascal caseUse verbs, verb phrases or verb-object pair to name methodsAlways mark public and protected methods as virtual/Overridable  in a non-sealed class. Methods with return values should have a name describing the value returnedDEMO
Method OverloadingUse method overloading to provide different methods that do semantically the same thing. Use method overloading instead of allowing default arguments. Overloaded methods should call the most complete methodIf you provide the ability to override a method, make only the most complete overload virtual and define the other operations in terms of itDEMO
Do Not Expose Generic ListList is a generic collection designed for performance not inheritance andApplies to public API’sDoes not contain any virtual membersCan not tell when updatedUse Instead:System.Collections.ObjectModel.CollectionSystem.Collections.ObjectModel.ReadOnlyCollectionSystem.Collections.ObjectModel.KeyedCollectionUse Interfaces:IDictionaryDEMO
Stop Exceptions BEFORE They Happen!Defensive Programming
Prevent ExceptionsPractice Defensive Programming!Any code that might cause an exception (accessing files, using objects like DataSets etc.) should check the object (depending on the type) so an Exception is not thrownFor example, call File.Exists to avoid a FileNotFoundExceptionCheck and object for nullCheck a DataSet for rowsCheck an Array for boundsCheck String for null or emptyDEMO
ParametersAlways check for valid parameter argumentsPerform argument validation for every public or protected methodThrow meaningful exceptions to the developer for invalid parameter argumentsUse the System.ArgumentException classOr your own class derived from System.ArgumentException DEMO
EnumsNever assume that Enum arguments will be in the defined range.Enums are just an Int32, so any valid number in that range could be sent in!Always use Enum.IsDefined to verify value before using!DEMO
TryParseUse the .TryParse method on value types when assigning from a string.WILL NOT cause an exception!Returns result of True/FalseDEMO
ExceptionsWhen doing any operation that could cause an exception, wrap in Try - Catch blockUse System.Environment.FailFast instead if unsafe for further executionDo not catch non-specific exceptions (for common API’s)Use Finally for cleanup codeWhen throwing Exceptions try using from System instead of creating custom ExceptionsUse MyApplication_UnhandledException event in VB.NET WinForm appsUse Application_Error event in ASP.NET apps
Code Style
VariablesAvoid single character variable namesi, t etc.Do not abbreviate variable words (such as num, instead of number)Unless they are well known like Xml, Html or IOIf deriving from a core type, add the suffix of the identify type. ArgumentException or FileStreamUse camel case for local variablesfirstName
Accessing Class Member VariablesPreface all calls to class members with this./Me., and place base./MyBase. before calls to all members of a base classClass BaseClass	Public Sub ProcessData()	End SubEnd ClassClass MainClass	Inherits BaseClass	Public Sub AnalyzeData()	End Sub	'Correct usage of this. and base.	Public Sub Good()		Me.AnalyzeData()		MyBase.ProcessData()	End Sub	'Incorrect usage.	Public Sub Bad()		AnalyzeData()		ProcessData()	End SubEnd Class
StringsWhen building a long string, always (almost) use StringBuilder, not string!C#StringBuilder builder = new StringBuilder("The error ");builder.Append(errorMessage); // errorMessage is defined elsewherebuilder.Append("occurred at ");builder.Append(DateTime.Now);Console.WriteLine(builder.ToString());VBDim builder As New StringBuilder("The error ")builder.Append(errorMessage)  'errorMessage is defined elsewherebuilder.Append("occurred at ")builder.Append(DateTime.Now)Console.WriteLine(builder.ToString())DEMO

Back-2-Basics: .NET Coding Standards For The Real World

  • 1.
    Back-2-Basics: .NET CodingStandards For The Real World
  • 3.
    Check Out YourLocal User Groups!San Diego Cloud Computing User Groupwww.azureusergroup.com/group/sandiegoazureusergroupSan Diego .NET Developers Groupwww.sddotnetdg.orgSan Diego .NET User Groupwww.sandiegodotnet.comSan Diego SQL Server User Groupwww.sdsqlug.org
  • 4.
    Win Free Software!RulesProvideyour business card (or email and name)*Indicate on the back what software you are interested inOtherwise I will pick Winners will be picked next week*Yes, most likely I’m going to send you and email about my user group (sddotnetdg.org) and or web site (dotNetTips.com)PrizesCodeRush and Refactor Pro from DevExpress (4)SecondCopy (automatic backup software) (5) *CodeIt.Right Standard from SubMain (4)*Requires mailing address and phone number
  • 5.
  • 6.
  • 7.
    Why Do YouNeed Standards?First, you might not agree witheverything I say… that’s okay!Pick a standard for your companyEvery programmer on the same pageEasier to read and understand codeEasier to maintain codeProduces more stable, reliable codeStick to the standard!!!
  • 8.
    After Selecting aStandardMake sure it’s easily available to each programmerPrint or electronicallyEnforce via code reviewsProvide programs to make it easier for programmers to maintain:StyleCop – Free for C# programmers.CodeIt.Right – Enterprise edition shares profiles. Can create custom profiles for your company.
  • 9.
    Real World AnalysisExampleScenario: In production Client Server Application with millions in salesNine projects of 183,177 lines of .NET code written by multiple programmers (junior to principal)StyleCopAnalyzeCode.It Right7,076< 1,1006,216< 2,5275,091< 1,837This is why you need to follow good coding practices throughout the lifecycle of the project!
  • 10.
  • 11.
  • 12.
    General Assembly TipsNeverhardcode strings that might change based on deployment such as connection stringsBest place to put them are in user or application level Settings in your application.Remember to save on exit and load on start!Automatic in VB.NET Other locations can include: Registration Database, Databases and more… DEMO
  • 13.
    General Assembly TipsSign(strong name) your assemblies, including the client applications. Also, sign interop assemblies with the project’s .snk fileName assemblies in the following format:<Company>.<Component>.dllProject names should be named the same.Microsoft.VisualBasic.dlldotNetTips.Utility.dllAcme.Services.References.dll
  • 14.
    Mark as CLSCompliantForces your assembly to be compliant with the Common Language Specification (CLS). Assemblies, modules, and types can be CLS-compliant even if some parts of the assembly, module, or type are not CLS-compliant, as long as these two conditions are met: If the element is marked as CLS-compliant, the parts that are not CLS-compliant must be marked using CLSCompliantAttribute with its argument set to false. A comparable CLS-compliant alternative member must be supplied for each member that is not CLS-compliant.DEMO
  • 15.
  • 16.
    Elements of theSame TypeShould appear in this order:public elementsprotected elementsinternal elementsprivate elementsUse #region/ #endregion to group namespace-level and class-level elementsUse separate regions to organize the private, protected, and internal members.
  • 17.
    NamespacesThe general rulefor naming namespaces is to use the company name followed by the technology name and optionally the feature and designCompanyName.TechnologyName[.Feature][.Design]
  • 18.
    EnumsUse abbreviations sparinglyfor Enums and their valuesDo not use an Enum suffix on Enum type namesUse a singular name for most Enum types, but use a plural name for Enum types that are bit fields
  • 19.
    EnumsAlways add theFlagsAttribute to a bit field Enum typeAvoid providing explicit values for Enums (unless necessary)Avoid specifying a type for an EnumPublic Enum WebServiceAction GetCurrentMode PauseService ResumeService StartService StopServiceEnd Enum
  • 20.
    InterfacesPrefix interface nameswith the letter “I”Do not use the underscore character. Use abbreviations sparingly.Challenging to version over releasesThe smaller, more focused the interface the betterpublic interface IDisposable{ // Methods void Dispose();}
  • 21.
    ClassesUse a nounor noun phrase to name a class.Avoid putting multiple classes in a single file.A file name should reflect the class it contains. Provide a default private constructor if there are only static methods and properties on a class. Use Static Class in C# or a Module in VB.NET
  • 22.
    EventsUse Pascal caseUsean EventHandler suffix on event handler names. Name an event argument class with the EventArgs suffix.Use EventHandler<> to declare handlers.Be careful with non-UI threads calling back to the UI!Use the BackgroundWorker Control in Windows FormsDEMO
  • 23.
    Member Variables (Fields)Usecamel case as a rule, or uppercase for very small wordsPrefix private variables with a "_”Member variables should not be declared publicUse a Property insteadConst member variables may be declared public
  • 24.
    PropertiesUse Pascal caseUsea noun or noun phrase to name propertiesProperties that return arrays or collections should be methods. Do not use write-only properties Consider providing events that are raised when certain properties are changed. Name them <Property>Changed
  • 25.
    PropertiesProperties should nothave dependencies on each otherSetting one property should not affect other propertiesProperties should be settable in any order.DEMO
  • 26.
    ConstructorsDo not callcode from a constructor!Can cause Exceptions.Capture parameters only.Provide a constructor for every class. Do not use the this./ Me. reference unless invoking another constructor from within a constructor.Provide a protected constructor that can be used by types in a derived class.
  • 27.
    DestructorsAvoid using destructors!Itis not possible to predict when garbage collection will occur.The garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams. Implement IDisposible if you do!Use the try/finally (or Using) to make sure that unmanaged resources are disposed of even if an exception interrupts your application. DEMO
  • 28.
    MethodsUse Pascal caseUseverbs, verb phrases or verb-object pair to name methodsAlways mark public and protected methods as virtual/Overridable in a non-sealed class. Methods with return values should have a name describing the value returnedDEMO
  • 29.
    Method OverloadingUse methodoverloading to provide different methods that do semantically the same thing. Use method overloading instead of allowing default arguments. Overloaded methods should call the most complete methodIf you provide the ability to override a method, make only the most complete overload virtual and define the other operations in terms of itDEMO
  • 30.
    Do Not ExposeGeneric ListList is a generic collection designed for performance not inheritance andApplies to public API’sDoes not contain any virtual membersCan not tell when updatedUse Instead:System.Collections.ObjectModel.CollectionSystem.Collections.ObjectModel.ReadOnlyCollectionSystem.Collections.ObjectModel.KeyedCollectionUse Interfaces:IDictionaryDEMO
  • 31.
    Stop Exceptions BEFOREThey Happen!Defensive Programming
  • 32.
    Prevent ExceptionsPractice DefensiveProgramming!Any code that might cause an exception (accessing files, using objects like DataSets etc.) should check the object (depending on the type) so an Exception is not thrownFor example, call File.Exists to avoid a FileNotFoundExceptionCheck and object for nullCheck a DataSet for rowsCheck an Array for boundsCheck String for null or emptyDEMO
  • 33.
    ParametersAlways check forvalid parameter argumentsPerform argument validation for every public or protected methodThrow meaningful exceptions to the developer for invalid parameter argumentsUse the System.ArgumentException classOr your own class derived from System.ArgumentException DEMO
  • 34.
    EnumsNever assume thatEnum arguments will be in the defined range.Enums are just an Int32, so any valid number in that range could be sent in!Always use Enum.IsDefined to verify value before using!DEMO
  • 35.
    TryParseUse the .TryParsemethod on value types when assigning from a string.WILL NOT cause an exception!Returns result of True/FalseDEMO
  • 36.
    ExceptionsWhen doing anyoperation that could cause an exception, wrap in Try - Catch blockUse System.Environment.FailFast instead if unsafe for further executionDo not catch non-specific exceptions (for common API’s)Use Finally for cleanup codeWhen throwing Exceptions try using from System instead of creating custom ExceptionsUse MyApplication_UnhandledException event in VB.NET WinForm appsUse Application_Error event in ASP.NET apps
  • 37.
  • 38.
    VariablesAvoid single charactervariable namesi, t etc.Do not abbreviate variable words (such as num, instead of number)Unless they are well known like Xml, Html or IOIf deriving from a core type, add the suffix of the identify type. ArgumentException or FileStreamUse camel case for local variablesfirstName
  • 39.
    Accessing Class MemberVariablesPreface all calls to class members with this./Me., and place base./MyBase. before calls to all members of a base classClass BaseClass Public Sub ProcessData() End SubEnd ClassClass MainClass Inherits BaseClass Public Sub AnalyzeData() End Sub 'Correct usage of this. and base. Public Sub Good() Me.AnalyzeData() MyBase.ProcessData() End Sub 'Incorrect usage. Public Sub Bad() AnalyzeData() ProcessData() End SubEnd Class
  • 40.
    StringsWhen building along string, always (almost) use StringBuilder, not string!C#StringBuilder builder = new StringBuilder("The error ");builder.Append(errorMessage); // errorMessage is defined elsewherebuilder.Append("occurred at ");builder.Append(DateTime.Now);Console.WriteLine(builder.ToString());VBDim builder As New StringBuilder("The error ")builder.Append(errorMessage) 'errorMessage is defined elsewherebuilder.Append("occurred at ")builder.Append(DateTime.Now)Console.WriteLine(builder.ToString())DEMO
  • 41.
    ParametersUse descriptive parameternamesParameter names should be descriptive enough such that the name of the parameter and its value can be used to determine its meaning in most scenariosDo not prefix parameter names with Hungarian type notationPublic Function ManageIIs(ByVal server As String, ByVal userName As String, ByVal password As System.Security.SecureString, ByVal domain As String, ByVal instance As String, ByVal action As IIsWebServiceAction) As Int32End Function
  • 42.
    Generic Type ParametersIfpossible use descriptive type parameters for generic parametersPrefix with TUse only T, K etc if is self-explanatoryC#public static string ConvertArrayToString<TArray>(TArray[] array) where TArray : IEnumerable { }VBPublic Shared Function ConvertArrayToString(Of TArray As {IEnumerable})(ByVal array As TArray()) As StringEnd FunctionDEMO
  • 43.
    CommentingComment your code!Whilecoding or beforeKeep it short and understandableMark changes with explanation, who changed it and the date (if that is your company standard)NEVER WAIT UNTIL AFTER YOU ARE DONE CODING!
  • 44.
    Xml CommentingNow supportedby VB.NET and C#!Comment all public classes and methods!XML can be turned into help docs, help html with applications like Sandcastlehttp://sandcastle.notlong.comVery useful for teams and documentation for users.Make this easy by using GhostDochttp://ghostdoc.notlong.comDEMO
  • 45.
    Let’s See WhatWe Have Learned/ KnowWhat’s Wrong With This Code?
  • 46.
    Constructorpublic class FileCache{ public FileCache(string tempPath)  {   var appData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),Global.UserDataFolder); var cacheDir = Path.Combine(appData, tempPath);    if (Directory.Exists(cacheDir) == false) {      Directory.CreateDirectory(cacheDir);  }   }}public class FileCache{ public FileCache(string tempPath)  {   this.TempPath = tempPath;  }}46
  • 47.
    Method public staticstring SQLValue(string parameter, string value){  if (String.IsNullOrEmpty(parameter))  {  throw new ArgumentNullException("parameter");  }   if (string.IsNullOrEmpty(value))    return (parameter + " = NULL");  else    return (parameter + " = '" + value.Trim() + "'");}public static string SQLValue(string parameter, string value){ if (String.IsNullOrEmpty(parameter))   {     throw new ArgumentNullException("parameter");    }   if (string.IsNullOrEmpty(value))   return (String.Format("{0} = NULL", parameter));   else    return (String.Format("{0} = '{1}'", parameter, value.Trim()));}public static string CreateSQLParameter(string name, string value){ if (String.IsNullOrEmpty(name))  {   throw new ArgumentNullException(”name");  }   return string.IsNullOrEmpty(value) ? (String.Format("{0} = NULL", name)) : (String.Format("{0} = '{1}'", name, value.Trim()));}public static string SQLValue(string name, string value){ if (string.IsNullOrEmpty(value))   return (name + " = NULL");  else   return (name + " = '" + value.Trim() + "'");}
  • 48.
    Exceptionprivate void UpdateVendor(){ try { //Code that causes and exception } catch (ValidationException ex) { //Clean up code throw ex; } catch (Exception ex) { LogWriter.WriteException(ex, System.Diagnostics.TraceEventType.Error, this.Name); }}
  • 49.
    Structure Public StructureUserInfo Private _contactName As String Public Property ContactName() As String Get Return _contactName End Get Set(ByVal value As String) _contactName = value End Set End Property Private _email As String Public Property Email() As String Get Return _email End Get Set(ByVal value As String) _email = value End Set End Property Public Overrides Function ToString() As String Return Me.ContactName End Function Public Overloads Overrides Function GetHashCode() As Integer Return Me.ContactName.GetHashCode Or Me.Email.GetHashCode End Function Public Overloads Overrides Function Equals(ByVal obj As [Object]) As Boolean Dim testObject As UserInfo = CType(obj, UserInfo) If Me.ContactName = testObject.ContactName AndAlso Me.Email = testObject.Email Return True Else Return False End If End Function End Structure Public Structure UserInfo Private _contactName As String Public Property ContactName() As String Get Return _contactName End Get Set(ByVal value As String) _contactName = value End Set End Property Private _email As String Public Property Email() As String Get Return _email End Get Set(ByVal value As String) _email = value End Set End Property Public Overrides Function ToString() As String Return Me.ContactName End FunctionPublic Overloads Overrides Function GetHashCode() As Integer Return Me.ContactName.GetHashCode Or Me.Email.GetHashCode End Function End Structure Public Structure UserInfo Private _contactName As String Public Property ContactName() As String Get Return _contactName End Get Set(ByVal value As String) _contactName = value End Set End Property Private _email As String Public Property Email() As String Get Return _email End Get Set(ByVal value As String) _email = value End Set End PropertyPublic Overrides Function ToString() As String Return Me.ContactName End FunctionEnd Structure Public Structure UserInfo Private _contactName As String Public Property ContactName() As String Get Return _contactName End Get Set(ByVal value As String) _contactName = value End Set End Property Private _email As String Public Property Email() As String Get Return _email End Get Set(ByVal value As String) _email = value End Set End PropertyEnd Structure
  • 50.
    Enumpublic enum MergeTypes{ InsCo = 1, Agents = 2, Vendors = 3}public enum MergeType{InsuranceCompanies, Agents, Vendors}public enum MergeType{None,InsuranceCompanies, Agents, Vendors}
  • 51.
    Fieldspublic class Contact{ protectedstring mNamePrefix = ""; protected string mFirstName = ""; protected string mLastName = ""; protected string mPhone1 = ""; protected string mExtension1 = ""; protected string mEmailAddress = ""; //Code}public class Contact{private string _namePrefix = string.Empty;protected string NamePrefix { get { return _namePrefix; } set { _namePrefix = value; } } //Code}
  • 52.
    Eventspublic delegate voidReportListEventHandler(object sender, ReportListEventArgs e);public event ReportListEventHandler ReportSelected;public event EventHandler<ReportListEventArgs> ReportSelected;
  • 53.
  • 54.
    Products To HelpOutStyleCophttp://stylecop.notlong.comCodeIt.Righthttp://codeitright.notlong.comFXCophttp://fxcop.notlong.comOr Use Analyze in VS Team SystemsRefactor Pro! For Visual Studiohttp://refactorpro.notlong.com I Use All 4!54
  • 55.
    Resourses (Besides MyBook)Design Guidelines for Class Library Developershttp://DGForClassLibrary.notlong.com.NET Framework General Reference Naming Guidelineshttp://namingguide.notlong.com

Editor's Notes

  • #9 C# Use Style Cope to enforce.
  • #27 DEMO: DefensiveProgramming.vb - SafeIntegerSet
  • #36 The original exception object should not be re-throwed explicitly. Violation of this rule will complicate debugging and ruin the exception&apos;s stack trace.
  • #37 ToStringGetHashCodeEquals
  • #38 Or use an automatic property!