C# Programming Guidelines
This final section of this chapter looks at
the guidelines you need to bear in mind when writing C#
programs.
Rules for Identifiers
This section examines the rules governing
what names you can use for variables, classes, methods, and so on.
Note that the rules presented in this section are not merely
guidelines: they are enforced by the C# compiler.
Identifiers are the names you give to variables, to
user-defined types such as classes and structs, and to members of
these types. Identifiers are case sensitive, so for example
variables named interestRate and
InterestRate would be recognized as
different variables. Following are a couple of rules determining
what identifiers you can use in C#:
-
They must begin with a letter or underscore,
although they can contain numeric characters.
-
You can’t use C# keywords as identifiers.
The following table lists the C# reserved
keywords.
If you do need to use one of these words as an
identifier (for example, if you are accessing a class written in a
different language), you can prefix the identifier with the
@ symbol to indicate to the compiler
that what follows is to be treated as an identifier, not as a C#
keyword (so abstract is not a valid
identifier, but @abstract is).
Finally, identifiers can also contain Unicode
characters, specified using the syntax \uXXXX, where XXXX is the
four-digit hex code for the Unicode character. The following are
some examples of valid identifiers:
-
Name
-
ĂĽberfluĂź
-
_Identifier
-
\u005fIdentifier
The last two items in this list are identical
and interchangeable (because 005f is the
Unicode code for the underscore character), so obviously these
identifiers couldn’t both be declared in the same scope. Note that
although syntactically you are allowed to use the underscore
character in identifiers, this isn’t recommended in most
situations, because it doesn’t follow the guidelines for naming
variables that Microsoft has written to ensure that developers use
the same conventions, making it easier to read each other’s
code.
Usage Conventions
In any development language, there usually
arise certain traditional programming styles. The styles are not
part of the language itself but are conventions concerning, for
example, how variables are named or how certain classes, methods,
or functions are used. If most developers using that language
follow the same conventions, it makes it easier for different
developers to understand each other’s code - which in turn
generally helps program maintainability. For example, a common
(though not universal) convention in Visual Basic 6 was that
variables that represents strings have names beginning with
lowercase s or lowercase str, as in the Visual Basic 6 statements
Dim sResult As String or Dim strMessage As String.
Conventions do, however, depend on the language and the
environment. For example, C++ developers programming on the Windows
platform have traditionally used the prefixes psz or lpsz to indicate
strings - char *pszResult; char
*lpszMessage; - but on Unix machines it’s more common not to
use any such prefixes: char *Result; char
*Message;.
You’ll notice from the sample code in this site
that the convention in C# is to name variables without prefixes:
string Result; string Message;.
|
|
Tip |
The convention by which variable names are
prefixed with letters that represent the data type is known as
Hungarian notation. It means that other developers reading the code
can immediately tell from the variable name what data type the
variable represents. Hungarian notation is widely regarded as
redundant in these days of smart editors and IntelliSense.
|
Whereas, with many languages, usage conventions
simply evolved as the language was used, with C# and the whole of
the .NET Framework Microsoft has written very comprehensive usage
guidelines, which are detailed in the .NET/C# MSDN documentation.
This should mean that, right from the start, .NET programs will
have a high degree of interoperability in terms of developers being
able to understand code. The guidelines have also been developed
with the benefit of some 20 years’ hindsight in object-oriented
programming, and as a result have been carefully thought out and
appear to have been well received in the developer community to
judge by the relevant newsgroups. Hence the guidelines are well
worth following.
It should be noted, however, that the guidelines
are not the same as language specifications. You should try to
follow the guidelines when you can. Nevertheless, you won’t run
into problems if you do have a good reason for not doing so - for
example, you won’t get a compilation error because you don’t follow
these guidelines. The general rule is that if you don’t follow the
usage guidelines you must have a convincing reason. Departing from
the guidelines should be a positive decision rather than simply not
bothering. Also, if you compare the guidelines with the samples in
the remainder of this site, you’ll notice that in numerous examples
in this site, we have chosen not to follow the conventions. That’s
usually because the conventions are designed for much larger
programs than our samples, and although they are great if you are writing a
complete software package, they are not really so suitable for
small 20-line standalone programs. In many cases, following the
conventions would have made our samples harder, rather than easier,
to follow.
The full guidelines for good programming style are
quite extensive. This section is confined to describing some of the
more important guidelines, as well as the ones most likely to
surprise you. If you want to make absolutely certain that your code
follows the usage guidelines completely, you will need to refer to
the MSDN documentation.
Naming Conventions
One important aspect to making your programs
understandable is how you choose to name your items - and that
includes naming variables, methods, classes, enumerations, and
namespaces.
It is intuitively obvious that your names should
reflect the purpose of the item and should be designed not to clash
with other names. The general philosophy in the .NET Framework is
also that the name of a variable should reflect the purpose of that
variable instance and not the data type. For example, height is a good name for a variable, whereas
integerValue isn’t. However, you will
probably feel that that principle is an ideal that is hard to
achieve. Particularly when you are dealing with controls, in most
cases, you’ll probably feel happier sticking with variable names
like confirmationDialog and chooseEmployeeListBox, which do indicate the data
type in the name.
The following sections look at some of the things
you need to think about when choosing names.
Casing of Names
In many cases you should use Pascal casing for names. Pascal casing means that
the first letter of each word in a name is capitalized:
EmployeeSalary, ConfirmationDialog, PlainTextEncoding. You will notice that essentially
all of the names of namespaces, classes, and members in the base
classes follow Pascal casing. In particular, the convention of
joining words using the underscore character is discouraged. So,
you should try not to use names like employee_salary. It has also been common in other
languages to use all capitals for names of constants. This is not
advised in C#, because such names are harder to read - the
convention is to use Pascal casing throughout:
The only other casing scheme that you are advised
to use is camel casing. Camel casing is
similar to Pascal casing, except that the first letter of the first
word in the name is not capitalized: employeeSalary, confirmationDialog, plainTextEncoding. Following are three situations in
which you are advised to use camel casing:
-
For names of all private member fields in
types:
Note, however, that often it is conventional to
prefix names of member fields with an underscore:
-
For names of all parameters passed to
methods:
-
To distinguish items that would otherwise
have the same name. A common example is when a property wraps
around a field:
If you are doing this, you should always use camel
casing for the private member and Pascal casing for the public or
protected member, so that other classes that use your code see only
names in Pascal case (except for parameter names).
You should also be wary about case
sensitivity. C# is case sensitive, so it is syntactically correct
for names in C# to differ only by the case, as in the previous
examples. However, you should bear in mind that your assemblies
might at some point be called from Visual Basic .NET applications -
and Visual Basic .NET
is not case sensitive. Hence, if you do use names that differ
only by case, it is important to do so only in situations in which
both names will never be seen outside your assembly. (The previous
example qualifies as okay because camel case is used with the name
that is attached to a private variable.)
Otherwise, you may prevent other code written in Visual Basic .NET
from being able to use your assembly correctly.
Name Styles
You should try to be consistent about your
style of names. For example, if one of the methods in a class is
called ShowConfirmationDialog(), then
you should not give another method a name like ShowDialogWarning() or WarningDialogShow(). The other method should be
called ShowWarningDialog().
Namespace Names
Namespace names are particularly important to
design carefully in order to avoid risk of ending up with the same
name for one of your namespaces as someone else uses. Remember,
namespace names are the only way that .NET
distinguishes names of objects in shared assemblies. So, if you use
the same namespace name for your software package as another
package, and both packages get installed on the same computer,
there are going to be problems. Because of this, it’s almost always
a good idea to create a top-level namespace with the name of your
company and then nest successive namespaces that narrow down the
technology, group, or department you are working in or the name of
the package your classes are intended for. Microsoft recommends
namespace names that begin with <CompanyName>.<TechnologyName> as in
these two examples:
Names and Keywords
It is important that the names do not clash
with any keywords. In fact, if you attempt to name an item in your
code with a word that happens to be a C# keyword, you’ll almost
certainly get a syntax error because the compiler will assume that
the name refers to a statement. However, because of the possibility
that your classes will be accessed by code written in other
languages, it is important that you also don’t use names that are
keywords in other .NET languages. Generally speaking, C++ keywords
are similar to C# keywords, so confusion with C++ is unlikely, and
those commonly encountered keywords that are unique to Visual C++
tend to start with two underscore characters. Like C#, C++ keywords
are spelled in lowercase, so if you hold to the convention of
naming your public classes and members with Pascal-style names,
they will always have at least one uppercase letter in their names,
and there will be no risk of clashes with C++ keywords. On the
other hand, you are more likely to have problems with Visual Basic
.NET, which has many more keywords than C# does, and being
non-case-sensitive means you cannot rely on Pascal-style names for
your classes and methods.
The following table lists the keywords and standard
function calls in Visual Basic .NET, which should if possible be
avoided, in whatever case combination, for your public C#
classes.
Use of Properties and Methods
One area that can cause confusion in a class
is whether a particular quantity should be represented by a
property or a method. The rules here are not hard and fast, but in
general, you ought to use a property if something really should
look and feel like a variable. (If you’re not sure what a property
is, see Chapter 3, “Objects and Types.”) This means,
among other things, that:
-
Client code should be able to read its value.
Write-only properties are not recommended, so for example use a
SetPassword() method, not a write-only
Password property.
-
Reading the value should not take too long.
The fact that something is a property usually suggests that reading
it will be relatively quick.
-
Reading the value should not have any
observable and unexpected side effect. Further, setting the value
of a property should not have any side effect that is not directly
related to the property. Setting the width of a dialog box has the
obvious effect of changing the appearance of the dialog box on the
screen. That’s fine, as that’s obviously related to the property in
question.
-
It should be possible to set properties in
any order. In particular, it is not good practice when setting a
property to throw an exception because another related property has
not yet been set. For example, if in order to use a class that
accesses a database, you need to set ConnectionString, UserName, and Password,
then the author of the class should make sure the class is
implemented so that the user really can set them in any order.
-
Successive reads of a property should give
the same result. If the value of a property is likely to change
unpredictably, you should code it up as a method instead.
Speed, in a class that monitors the
motion of an automobile, is not a good candidate for a property.
Use a GetSpeed() method here; on the
other hand, Weight and EngineSize are good candidates for properties
because they will not change for a given object.
If the item you are coding satisfies all of
the preceding criteria, it is probably a good candidate for a
property. Otherwise, you should use a method.
Use of Fields
The guidelines are pretty simple here. Fields
should almost always be private, except that in some cases it may
be acceptable for constant or read-only fields to be public. The
reason is that if you make a field public, you may hinder your
ability to extend or modify the class in the future.
The previous guidelines should give you a rough
idea of good practices, and you should also use them in conjunction
with good object-oriented programming style.
It’s also worth bearing in mind that Microsoft
has been fairly careful about being consistent and has followed its
own guidelines when writing the .NET base classes. So a very good
way to get an intuitive feel for the conventions to follow when
writing .NET code is to simply look at the base classes - see how
classes, members, and namespaces are named, and how the class
hierarchy works. If you try to write your code in the same style as
the base classes, you shouldn’t go wrong.
|