Following a consistent set of naming conventions in the development of a framework can be a major contribution to the framework’s usability. It allows the framework to be used by many developers on widely separated projects. Beyond consistency of form, names of framework elements must be easily understood and must convey the function of each element.
The goal of this chapter is to provide a consistent set of naming conventions that results in names that make immediate sense to developers. Most of these naming guidelines are simply conventions that have no technical rationale. However, following them will ensure that the names are understandable and consistent.
Although adopting these naming conventions as general code development guidelines would result in more consistent naming throughout your code, the guidance here only applies to APIs that are publicly exposed (public or protected types and members, and parameters to public or protected members).
This chapter describes general naming guidelines, including how to use capitalization, mechanics, and certain specific terms. It also provides specific guidelines for naming namespaces, types, members, parameters, assemblies, and resources.
Because the Common Language Runtime (CLR) supports many languages that might or might not be case sensitive, case alone should not be used to differentiate names. However, the importance of case in enhancing the readability of names cannot be overemphasized. The guidelines in this chapter lay out a simple method for using case that, when applied consistently, make identifiers for types, members, and parameters easy to read.
To differentiate words in an identifier, capitalize the first letter of each word in the identifier. Do not use underscores to differentiate words, or for that matter, anywhere in identifiers. There are two appropriate ways to capitalize identifiers, depending on the use of the identifier:
PascalCasing
camelCasing
The PascalCasing convention, used for all identifiers except parameter names, capitalizes the first character of each word (including acronyms more than two letters in length), as shown in the following examples:
PropertyDescriptor HtmlTag
A special case is made for two-letter acronyms in which both letters are capitalized, as shown in the following identifier:
IOStream
The camelCasing convention, used only for parameter names, capitalizes the first character of each word except the first word, as shown in the following examples. As the example also shows, two-letter acronyms that begin a camel-cased identifier are both lowercase.
propertyDescriptor ioStream htmlTag
The following are two basic capitalization guidelines for identifiers:
DO use PascalCasing for the names of namespaces, types, members, and generic type parameters.
For example, use TextColor
rather than Textcolor
or Text_color
. Single words, such as Button
, simply have initial capitals. Compound words that are always written as a single word, like endpoint, are treated as single words and have initial capitals only. More information on compound words is given in section 3.1.3.
DO use camelCasing for parameter names.
Table 3-1 describes the capitalization rules for different types of identifiers.
Table 3-1: Capitalization Rules for Different Types of Identifiers
Identifier |
Casing |
Example |
---|---|---|
Namespace |
Pascal |
namespace System.Security { ... } |
Type |
Pascal |
public class StreamReader { ... } |
Interface |
Pascal |
public interface IEnumerable { ... } |
Method |
Pascal |
public class Object { |
Property |
Pascal |
public class String { |
Event |
Pascal |
public class Process { |
Field |
Pascal |
public class MessageQueue { |
Enum value |
Pascal |
public enum FileMode { |
Type parameter, generic method |
Pascal |
public partial class Enum { |
Type parameter, generic type |
Pascal |
public class Task<TResult> { |
Tuple element |
Pascal |
public partial class Range { |
Parameter |
Camel |
public class Convert { |
In general, it is important to avoid using acronyms in identifier names unless they are in common usage and are immediately understandable to anyone who might use the framework. For example, HTML, XML, and IO are all well understood, but less well-known acronyms should definitely be avoided.
By definition, an acronym must be at least two characters. Acronyms of three or more characters follow the guidelines of any other word. Only the first letter is capitalized, unless it is the first word in a camel-cased parameter name, which is all lowercase.
As mentioned in the preceding section, two-character acronyms (e.g., IO) are treated differently, primarily to avoid confusion. Both characters should be capitalized unless the two-character acronym is the first word in a camel-cased parameter name, in which case both characters are lowercase. The following examples illustrate all of these cases:
public void StartIO(Stream ioStream, bool closeIOStream); public void ProcessHtmlTag(string htmlTag)
DO capitalize both characters of two-character acronyms, except the first word of a camel-cased identifier.
System.IO System.Threading.IOCompletionCallback public void StartIO(Stream ioStream)
DO capitalize only the first character of acronyms with three or more characters, except the first word of a camel-cased identifier.
System.Xml System.Xml.XmlNode public void ProcessHtmlTag(string htmlTag)
DO NOT capitalize any of the characters of any acronyms, whatever their length, at the beginning of a camel-cased identifier.
Most compound terms are treated as single words for purposes of capitalization.
DO NOT capitalize each word in so-called closed-form compound words.
These are compound words written as a single word, such as endpoint. For the purpose of casing guidelines, treat a closed-form compound word as a single word. Use a current dictionary to determine if a compound word is written in closed form.
Table 3-2 shows capitalization for some of the most commonly used compound words and common terms.
Table 3-2: Capitalization and Spelling for Common Compound Words and Common Terms
Pascal |
Camel |
Not |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. When used as a noun (properties, fields, parameters, types). As a verb (methods) it should be considered two words—for example, LogOff
.
2. “Login” is now regarded as a closed-form noun, so a type with members named “Login” and “Password” would be OK, except in .NET we prefer “Logon” to “Login.” As a compound verb, “Log In” should be “Log On,” so “LogIn” is never used, and “LogOn” does not appear in this table.
Two other terms that are in common usage are in a category by themselves, because they are common slang abbreviations. The two words Ok and Id (cased as shown here) are exceptions to the guideline that no abbreviations should be used in names.
Table 3-2 and the rule about closed-form nouns are secondary to the general guideline of maintaining consistency. As of September 2019, “white space” is the dictionary entry, with some dictionaries having a note that computer science often uses it as a single word. If and when “whitespace” becomes an accepted closed-form noun, you should continue to use “WhiteSpace” in type hierarchies built with the older form of the word.
Languages that can run on the CLR are not required to support case sensitivity, although some do. Even if your language supports it, other languages that might access your framework do not. Any APIs that are externally accessible, therefore, cannot rely on case alone to distinguish between two names in the same context.
There is really only one guideline for case sensitivity, albeit an important one.
DO NOT assume that all programming languages are case sensitive. They are not. Names cannot differ by case alone.
This section describes general naming conventions that relate to word choice, guidelines on using abbreviations and acronyms, and recommendations on how to avoid using language-specific names.
It is important that names of framework identifiers make sense on first reading. Identifier names should clearly state what each member does and what each type and parameter represents. To this end, it is more important that the name be clear than that it be short. Names should correspond to scenarios, logical or physical parts of the system, and well-known concepts, rather than to technologies or architecture.
DO choose easily readable identifier names.
For example, a property named HorizontalAlignment
is more English-readable than AlignmentHorizontal
.
DO favor readability over brevity. The property name CanScrollHorizontally
is better than ScrollableX
(an obscure reference to the X-axis).
DO NOT use underscores, hyphens, or any other non-alphanumeric characters.
DO NOT use Hungarian notation.
AVOID using identifiers that conflict with keywords of widely used programming languages.
According to Rule 4 of the Common Language Specification (CLS), all compliant languages must provide a mechanism that allows access to named items that use a keyword of that language as an identifier. C#, for example, uses the @ sign as an escape mechanism in this case. However, it is still a good idea to avoid common keywords because it is much more difficult to use a method with the escape sequence than one without it.
DO use only ASCII characters in identifier names.
All of the identifiers in .NET use ASCII characters, so anyone working with .NET is capable of typing those characters and working with files or tools that understand those characters. But the developers who want to use your library may not have easy capability to type non-ASCII characters, or may use text editors (or other tools) that do not reliably preserve non-ASCII data.
When basing an identifier on a word that properly requires diacritical marks, either use (or invent) the diacritical-free approximation or choose a different identifier.
Table 3-3 describes some suggested replacement spellings to avoid diacritical marks. It is provided for clarity, but is neither authoritative nor exhaustive.
Table 3-3: Alternative Spellings to Avoid Diacritical Marks
Spelling with Diacritics |
Spelling for an Identifier |
---|---|
|
|
|
|
|
|
|
|
|
|
In general, do not use abbreviations or acronyms in identifiers. As stated earlier, it is more important for names to be readable than it is for them to be brief. It is equally important not to use abbreviations and acronyms that are not generally understood—that is, do not use anything that the large majority of people who are not experts in a given field would not know the meaning of immediately.
DO NOT use abbreviations or contractions as part of identifier names.
For example, use GetWindow
rather than GetWin
.
DO NOT use any acronyms that are not widely accepted, and even if they are, only when necessary.
For example, UI is used for User Interface and HTML is used for HyperText Markup Language. Although many framework designers feel that some recent acronym will soon be widely accepted, it is bad practice to use it in framework identifiers.
For acronym capitalization rules, see section 3.1.2.
Programming languages that target the CLR often have their own names (aliases) for the so-called primitive types. For example, int
is a C# alias for System.Int32
. To ensure that your framework can take full advantage of the cross-language interoperation that is one of the core features of the CLR, it is important to avoid the use of these language-specific type names in identifiers.
DO use semantically interesting names rather than language-specific keywords for type names.
For example, GetLength
is a better name than GetInt
.
DO use a generic CLR type name, rather than a language-specific name, in the rare cases when an identifier has no semantic meaning beyond its type.
For example, a method converting to System.Int64
should be named ToInt64
, not ToLong
(because System.Int64
is a CLR name for the C#-specific alias long
). Table 3-4 presents several base data types using the CLR type names (as well as the corresponding type names for C#, Visual Basic, and C++).
Table 3-4: CLR Type Names for Language-Specific Type Names
C# |
Visual Basic |
C++ |
CLR |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DO use a common name, such as value or item, rather than repeating the type name, in the rare cases when an identifier has no semantic meaning and the type of the parameter is not important.
The following is a good example of methods of a class that support writing a variety of data types into a stream:
void Write(double value); void Write(float value); void Write(short value);
Sometimes a new feature cannot be added to an existing type, even though the type’s name implies that it is the best place for the new feature. In such a case, a new type needs to be added, which often leaves the framework designer with the difficult task of finding a good new name for the new type. Similarly, an existing member often cannot be extended or overloaded to provide additional functionality, so a member with a new name needs to be added. The guidelines that follow describe how to choose names for new types and members that supersede or replace existing types or members.
DO use a name similar to the old API when creating new versions of an existing API.
This helps to highlight the relationship between the APIs.
class AppDomain { [Obsolete("AppDomain.SetCachePath has been deprecated. Please use AppDomainSetup.CachePath instead.")] public void SetCachePath(String path) { ... } } class AppDomainSetup { public string CachePath { get { ... }; set { ... }; } }
DO prefer adding a suffix rather than a prefix to indicate a new version of an existing API.
CONSIDER using a brand-new, but meaningful, identifier, instead of adding a suffix or a prefix.
DO use a numeric suffix to indicate a new version of an existing API, particularly if the existing name of the API is the only name that makes sense (e.g., if it is an industry standard) and if adding any meaningful suffix (or changing the name) is not an appropriate option.
// old API [Obsolete("This type is obsolete. Please use the new version of the same class, X509Certificate2.")] public class X509Certificate { ... } // new API public class X509Certificate2 { ... }
DO NOT use the “Ex” (or a similar) suffix for an identifier to distinguish it from an earlier version of the same API.
[Obsolete("This type is obsolete. ...")] public class Car { ... } // new API public class CarEx { ... } // the wrong way public class CarNew { ... } // the wrong way public class Car2 { ... } // an acceptable way public class Automobile { ... } // a better way
DO use the “64” suffix when introducing versions of APIs that operate on a 64-bit integer (a long integer) instead of a 32-bit integer. You only need to take this approach when the existing 32-bit API exists; don’t do it for brand-new APIs with only a 64-bit version.
For example, various APIs on System.Diagnostics.Process
return Int32
values representing memory sizes, such as PagedMemorySize
or PeakWorkingSet
. To appropriately support these APIs on 64-bit systems, APIs have been added that have the same name but a “64” suffix.
public class Process { // old APIs public int PeakWorkingSet { get; } public int PagedMemorySize { get; } // ... // new APIs public long PeakWorkingSet64 { get; } public long PagedMemorySize64 { get; } }
An assembly is the unit of deployment and identity for managed code programs. Although assemblies can span one or more files, typically an assembly maps one-to-one with a dynamic-link library (DLL). Additionally, when a DLL is distributed via a package management system, the DLL and the package typically have the same name. Therefore, this section describes only DLL naming conventions, which then can be mapped to assembly naming conventions and package naming conventions.
Keep in mind that namespaces are distinct from DLL and assembly names. Namespaces represent logical groupings for developers, whereas DLLs and assemblies represent packaging and deployment boundaries. DLLs can contain multiple namespaces for product factoring and other reasons. Because namespace factoring is different than DLL factoring, you should design them independently. For example, if you decide to name your DLL MyCompany.MyTechnology
, it does not mean that the DLL has to contain a namespace named MyCompany.MyTechnology
, though it can.
DO choose names for your assembly DLLs that suggest large chunks of functionality, such as System.Data
.
Assembly, DLL, and package names don’t have to correspond to namespace names, but it is reasonable to follow the namespace name when naming assemblies. A good rule of thumb is to name the DLL based on the common prefix of the namespaces contained in the assembly. For example, an assembly with two namespaces, MyCompany.MyTechnology.FirstFeature
and MyCompany.MyTechnology.SecondFeature
, could be called MyCompany.MyTechnology.dll
.
CONSIDER naming DLLs according to the following pattern:
<Company>.<Component>.dll
<Component>
can contain more than one dot-separated clauses. For example:
Microsoft.VisualBasic.dll Microsoft.VisualBasic.Vsa.dll Fabrikam.Security.dll Litware.Controls.dll
As with other naming guidelines, the goal when naming namespaces is to create sufficient clarity for the programmer using the framework to immediately know what the content of the namespace is likely to be. The following template specifies the general rule for naming namespaces:
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
The following are examples:
Microsoft.VisualStudio Microsoft.VisualStudio.Design Fabrikam.Math Litware.Security
DO prefix namespace names with a company name to prevent namespaces from different companies from having the same name.
For example, the Microsoft Office automation APIs provided by Microsoft should be in the namespace Microsoft.Office
.
DO use a stable, version-independent product name at the second level of a namespace name.
DO NOT use organizational hierarchies as the basis for names in namespace hierarchies, because group names within corporations tend to be short-lived. Organize the hierarchy of namespaces around groups of related technologies.
DO use PascalCasing, and separate namespace components with periods (e.g., Microsoft.Office.PowerPoint
). If your brand employs nontraditional casing, you should follow the casing defined by your brand, even if it deviates from normal namespace casing.
CONSIDER using plural namespace names where appropriate.
For example, use System.Collections
instead of System.Collection
. Brand names and acronyms are exceptions to this rule, however. For example, use System.IO
instead of System.IOs
.
DO NOT use the same name for a namespace and a type in that namespace.
For example, do not use Debug
as a namespace name and then also provide a class named Debug
in the same namespace. Several compilers require such types to be fully qualified.
These guidelines cover general namespace naming guidelines, but the next section provides specific guidelines for certain special subnamespaces.
Namespaces are used to organize types into a logical and easy-to-explore hierarchy. They are also indispensable in resolving type name ambiguities that might arise when importing multiple namespaces. However, that fact should not be used as an excuse to introduce known ambiguities between types in different namespaces that are commonly used together. Developers should not be required to qualify type names in common scenarios.
DO NOT introduce overly general type names such as Element
, Node
, Log
, and Message
.
There is a very high probability that doing so will lead to type name conflicts in common scenarios. You should qualify the general type names (e.g., FormElement
, XmlNode
, EventLog
, SoapMessage
).
There are specific guidelines for avoiding type name conflicts for different categories of namespaces. Namespaces can be divided into the following categories:
Application model namespaces
Infrastructure namespaces
Core namespaces
Technology namespace groups
Namespaces belonging to a single application model are very often used together, but they are almost never used with namespaces of other application models. For example, the System.Windows.Forms
namespace is very rarely used together with the System.Web.UI
namespace. The following are well-known application model namespace groups:
System.Windows* System.Web.UI*
DO NOT give the same name to multiple types across namespaces within a single application model.
For example, do not add a type named Page
to the System.Web.UI.Adapters
namespace, because the System.Web.UI
namespace already contains a type named Page
.
This group contains namespaces that are rarely imported during development of common applications. For example, .Design
namespaces are mainly used when developing programming tools. Avoiding conflicts with types in these namespaces is not critical.
System.Windows.Forms.Design *.Design *.Permissions
The core namespaces include all System
namespaces, excluding namespaces of the application models and the Infrastructure namespaces. Core namespaces include, among others, System
, System.IO
, System.Xml
, and System.Net
.
DO NOT give types names that would conflict with any type in the core namespaces.
For example, never use Stream
as a type name. It would conflict with System.IO.Stream
, a very commonly used type.
By the same token, do not add a type named EventLog
to the System.Diagnostics.Events
namespace, because the System.Diagnostics
namespace already contains a type named EventLog
.
This category includes all namespaces with the same first two namespace nodes (<Company>.<Technology>*
), such as Microsoft.Build.Utilities
and Microsoft.Build.Tasks
. It is important that types belonging to a single technology do not conflict with each other.
DO NOT assign type names that would conflict with other types within a single technology.
DO NOT introduce type name conflicts between types in technology namespaces and an application model namespace (unless the technology is not expected to be used with the application model).
For example, you should not add a type named Binding
to the Microsoft.VisualBasic
namespace because the System.Windows.Forms
namespace already contains that type name.
In general, class and struct names should be nouns or noun phrases, because they represent entities of the system. A good rule of thumb is that if you are not able to come up with a noun or a noun phrase name for a class or a struct, you probably should rethink the general design of the type. Interfaces representing roots of a hierarchy (e.g., IList<T>
) should also use nouns or noun phrases. Interfaces representing capabilities should use adjectives and adjective phrases (e.g., IComparable<T>
, IFormattable
).
Another important consideration is that the most easily recognizable names should be used for the most commonly used types, even if the name fits some other less-used type better in the purely technical sense. For example, a type used in mainline scenarios to submit print jobs to print queues should be named Printer
, rather than PrintQueue
. Even though technically the type represents a print queue and not the physical device (printer), from the scenario point of view, Printer
is the ideal name because most people are interested in submitting print jobs and not in other operations related to the physical printer device (e.g., configuring the printer). If you need to provide another type that corresponds, for example, to the physical printer to be used in configuration scenarios, the type could be called PrinterConfiguration
or PrinterManager
.
Similarly, names of the most commonly used types should reflect usage scenarios, not inheritance hierarchy. Most users use the leaves of an inheritance hierarchy almost exclusively; they are rarely concerned with the structure of the hierarchy. Yet API designers often see the inheritance hierarchy as the most important criterion for type name selection. For example, Stream
, StreamReader
, TextReader
, StringReader
, and FileStream
all describe the place of each of the types in the inheritance hierarchy quite well, but they obscure the most important information for the majority of users: the type that they need to instantiate to read text from a file.
The naming guidelines that follow apply to general type naming.
DO name classes and structs with nouns or noun phrases, using PascalCasing.
This distinguishes type names from methods, which are named with verb phrases.
DO name interfaces with adjective phrases, or occasionally with nouns or noun phrases.
Nouns and noun phrases should be used rarely. They might indicate that the type should be an abstract class, rather than an interface. See section 4.3 for details about deciding how to choose between abstract classes and interfaces.
DO NOT give class names a prefix (e.g., “C”).
CONSIDER ending the name of derived classes with the name of the base class.
This is very readable and explains the relationship clearly. Two examples of this in code are ArgumentOutOfRangeException
, which is a kind of Exception
, and SerializableAttribute
, which is a kind of Attribute
. However, it is important to use reasonable judgment in applying this guideline; for example, the Button
class is a kind of Control
, although Control
doesn’t appear in its name. The following are examples of correctly named classes:
public class FileStream : Stream {...} public class Button : Control {...}
DO prefix interface names with the letter I, to indicate that the type is an interface.
For example, IComponent
(descriptive noun), ICustomAttributeProvider
(noun phrase), and IPersistable
(adjective) are appropriate interface names. As with other type names, avoid abbreviations.
DO ensure that the names differ only by the “I” prefix on the interface name when you are defining a class–interface pair where the class is a standard implementation of the interface.
The following example illustrates this guideline for the interface IComponent
and its standard implementation, the class Component
:
public interface IComponent { ... } public class Component : IComponent { ... }
Generics were added to .NET Framework 2.0. This feature introduced a new kind of identifier called type parameter. The following guidelines describe naming conventions related to naming such type parameters:
DO name generic type parameters with descriptive names unless a single-letter name is completely self-explanatory and a descriptive name would not add value.
public interface ISessionChannel<TSession> { ... } public delegate TOutput Converter<TInput,TOutput>(TInput from); public struct Nullable<T> { ... } public class List<T> { ... }
CONSIDER using T
as the type parameter name for types with one single-letter type parameter.
public int IComparer<T> { ... } public delegate bool Predicate<T>(T item); public struct Nullable<T> where T:struct { ... }
DO prefix descriptive type parameter names with T
.
public interface ISessionChannel<TSession> where TSession : ISession{ TSession Session { get; } }
CONSIDER indicating constraints placed on a type parameter in the name of the parameter.
For example, a parameter constrained to ISession
might be called TSession
.
If you are deriving from or implementing types contained in .NET, it is important to follow the guidelines in this section.
DO follow the guidelines described in Table 3-5 when naming types derived from or implementing certain .NET types.
Table 3-5: Name Rules for Types Derived from or Implementing Certain Core Types
Base Type |
Derived/Implementing Type Guideline |
---|---|
|
DO add the suffix “Attribute” to names of custom attribute classes. |
|
DO add the suffix “EventHandler” to names of delegates that are used in events. DO add the suffix “Callback” to names of delegates other than those used as event handlers. DO NOT add the suffix “Delegate” to a delegate. |
|
DO add the suffix “EventArgs.” |
|
DO NOT derive from this class; use the keyword supported by your language instead; for example, in C#, use the DO NOT add the suffix “Enum” or “Flag.” |
|
DO add the suffix “Exception.” |
|
DO add the suffix “Dictionary.” Note that |
|
DO add the suffix “Collection,” except for reusable, specialized data types such as “Queue” and “HashSet.” |
|
DO add the suffix “Stream.” |
These suffixing guidelines apply to the whole hierarchy of the specified base type. For example, it is not just types derived directly from System.Exception
that need the suffixes, but also those derived from Exception
subclasses.
These suffixes should be reserved for the named types. Types derived from or implementing other types should not use these suffixes. For example, the following represent incorrect naming:
public class ElementStream : Object { ... } public class WindowsAttribute : Control { ... }
Names of enumeration types (also called enums) in general should follow the standard type-naming rules (PascalCasing, etc.). However, there are additional guidelines that apply specifically to enums.
DO use a singular type name for an enumeration unless its values are bit fields.
public enum ConsoleColor { Black, Blue, Cyan, ... }
DO use a plural type name for an enumeration with bit fields as values, also called flags enum.
[Flags] public enum ConsoleModifiers { Alt = 1 << ʘ, Control = 1 << 1, Shift = 1 << 2, }
DO NOT use an “Enum” suffix in enum type names.
For example, the following enum is badly named:
// Bad naming public enum ColorEnum { ... }
DO NOT use “Flag” or “Flags” suffixes in enum type names.
For example, the following enum is badly named:
// Bad naming [Flags] public enum ColorFlags { ... }
DO NOT use a prefix on enumeration value names (e.g., “ad” for ADO enums, “rtf” for rich text enums).
public enum ImageMode { ImageModeBitmap = ʘ, // ImageMode prefix is not necessary ImageModeGrayscale = 1, ImageModeIndexed = 2, ImageModeRgb = 3, }
The following naming scheme would be better:
public enum ImageMode { Bitmap = ʘ, Grayscale = 1, Indexed = 2, Rgb = 3, }
Types are made of members: methods, properties, events, constructors, and fields. The following sections describe guidelines for naming type members.
Because methods are the means of taking action, the design guidelines require that method names be verbs or verb phrases. Following this guideline also serves to distinguish method names from property and type names, which are noun or adjective phrases.
DO give methods names that are verbs or verb phrases.
public class String { public int CompareTo(...); public string[] Split(...); public string Trim(); }
Unlike other members, properties should be given noun phrase or adjective names. That is because a property refers to data, and the name of the property reflects that. PascalCasing is always used for property names.
DO name properties using a noun, noun phrase, or adjective.
public class String { public int Length { get; } }
DO NOT have properties that match the name of “Get” methods, such as a property named TextWriter
and a method named GetTextWriter
.
public string TextWriter { get {...} set {...} } public string GetTextWriter(int value) { ... }
This pattern typically indicates that the property should really be a method. See section 5.1.3 for additional information.
DO name collection properties with a plural phrase describing the items in the collection instead of using a singular phrase followed by “List” or “Collection.”
public class ListView { // good naming public ItemCollection Items { get; } // bad naming public ItemCollection ItemCollection { get; } }
DO name Boolean properties with an affirmative phrase (CanSeek
instead of CantSeek
). Optionally, you can also prefix Boolean properties with “Is,” “Can,” or “Has,” but only where it adds value.
For example, CanRead
is more understandable than Readable
. However, Created
is actually more readable than IsCreated
. Having the prefix is often too verbose and unnecessary, particularly in the face of IntelliSense in the code editors. It is just as clear to type MyObject.Enabled =
and have IntelliSense give you the choice of true or false as it is to have MyObject.IsEnabled =
, and the second approach is more verbose.
CONSIDER giving a property the same name as its type.
For example, the following property correctly gets and sets an enum value named Color
, so the property is named Color
:
public enum Color {...} public class Control { public Color Color { get; set; } }
Events always refer to some action, either one that is happening or one that has occurred. Therefore, as with methods, events are named with verbs, and verb tense is used to indicate the time when the event is raised.
DO name events with a verb or a verb phrase.
Examples include Clicked
, Painting
, and DroppedDown
.
DO give events names with a concept of before and after, using the present and past tenses, such as Closing
and Closed
.
For example, a close event that is raised before a window is closed would be called Closing
, and one that is raised after the window is closed would be called Closed
.
DO NOT use “Before” or “After” prefixes or postfixes to indicate pre- and post-events. Use present and past tenses as just described.
DO name event handlers (delegates used as types of events) with the “EventHandler” suffix, such as ClickedEventHandler
.
public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);
Note that you should create custom event handlers very rarely. Instead, most APIs should simply use EventHandler<T>
. Section 5.4.1 talks about event design in more detail.
DO use two parameters named sender and e in event handlers.
The sender parameter represents the object that raised the event. The sender parameter is typically of type object
, even if it is possible to employ a more specific type. The pattern is used consistently across .NET and is described in more detail in section 5.4.
public delegate void <EventName>EventHandler(object sender, <EventName>EventArgs e);
DO name event argument classes with the “EventArgs” suffix, as shown in the following example:
public class ClickedEventArgs : EventArgs { int x; int y; public ClickedEventArgs (int x, int y) { this.x = x; this.y = y; } public int X { get { return x; } } public int Y { get { return y; } } }
The field-naming guidelines apply to static public and protected fields. Internal and private fields are not covered by guidelines, and public or protected instance fields are not allowed by the member design guidelines, which are described in Chapter 5.
DO use PascalCasing in field names.
public class String { public static readonly string Empty = ""; } public struct UInt32 { public const MinValue = ʘ; }
DO name fields using a noun, noun phrase, or adjective.
DO NOT use a prefix for public
or protected
field names.
For example, do not use “g_” or “s_” to indicate static fields. Publicly accessible fields (the subject of this section) are very similar to properties from the API design point of view; therefore, they should follow the same naming conventions as properties.
Beyond the obvious reason of readability, it is important to follow the guidelines for parameter names because parameters are displayed in documentation and in the designer when visual design tools provide IntelliSense and class browsing functionality.
DO use camelCasing in parameter names.
public class String { public bool Contains(string value); public string Remove(int startIndex, int count); }
DO use descriptive parameter names.
Parameter names should be descriptive enough to use with their types to determine their meaning in most scenarios.
CONSIDER using names based on a parameter’s meaning rather than the parameter’s type.
Development tools generally provide useful information about the type, so the parameter name can be put to better use describing semantics rather than the type. Occasional use of type-based parameter names is entirely appropriate—but it is not ever appropriate under these guidelines to revert to the Hungarian naming convention.
This section discusses naming parameters of operator overloads.
DO use left and right for binary operator overload parameter names if there is no meaning to the parameters.
public static TimeSpan operator-(DateTimeOffset left, DateTimeOffset right) public static bool operator==(DateTimeOffset left, DateTimeOffset right)
DO use value for unary operator overload parameter names if there is no meaning to the parameters.
public static BigInteger operator-(BigInteger value);
CONSIDER meaningful names for operator overload parameters if doing so adds significant value.
public static BigInteger Divide(BigInteger dividend, BigInteger divisor);
DO NOT use abbreviations or numeric indices for operator overload parameter names.
// incorrect parameter naming public static bool operator ==(DateTimeOffset d1, DateTimeOffset d2);
The guidance from this section in previous editions is obsolete, and has been archived in Appendix B.
DO NOT directly expose localizable resources as public (or protected) members.
The types and members automatically generated by a resource editor should use the internal
access modifier.
When it does make sense to expose a resource via public API, use intentional type and member design.
The naming guidelines described in this chapter, if followed, provide a consistent scheme that will make it easy for users of a framework to identify the function of elements of the framework. The guidelines provide naming consistency across frameworks developed by different organizations or companies.
The next chapter provides general guidelines for implementing types.
3.142.195.24