Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro .NET 2.0 Code And Design Standards In CSharp (2006) [eng]

.pdf
Скачиваний:
34
Добавлен:
16.08.2013
Размер:
3.43 Mб
Скачать

26C H A P T E R 1 C O D E P O L I C Y

Spacing for delimiters

Insert space after colon for base or interface in type declaration

Insert space after comma

Insert space after dot

Insert space after semicolon in “for” statement

Insert space before colon for base or interface in type declaration

Insert space before comma

Insert space before dot

Insert space before semicolon in for statement

Spacing for operators

Insert space before and after binary operators

Ignore spaces around binary operators

Remove white space before and after binary operators

Wrapping

Leave block on single line

Leave statements and member declarations on the same line

Supplementary Style Policy

Case sensitivity is not a standard that fits within code notation or formatting policy, but it is inserted into code policy as a supplementary style policy—as are other standards that are appropriate.

Case Sensitivity

.NET comes with two types of development languages, case sensitive (e.g., C#) and case insensitive (e.g., Visual Basic). This presents a bit of a problem for teams that support both language types, and so there is always an option to accept a .NET standard, which rules against using case sensitivity (e.g., in C# language).

What

Case sensitivity refers to a language that recognizes that code syntax can be differentiated on case.

C H A P T E R 1 C O D E P O L I C Y

27

Where

Alpha characters are case sensitive in the C# language and are not in Visual Basic language.

Why

Case sensitivity is leveraged by developers for convenience and readability.

How

A variable name is differentiated by case; for example, in C# language the following variable (car) is differentiated, by the compiler, from its type (Car):

Car car; (C#)

However, in Visual Basic the equivalent syntax would result in a compile error:

Dim car as Car (VB)

To maintain a consistent variable naming style across the languages, a common practice is to (1) rule against the use of case sensitivity in C# code; or (2) prefix a variable with an underscore in both languages, as in the following example:

Car _car; (C#)

Dim _car as Car (VB)

The Standard: Case Sensitivity

The standard acknowledges that where C# and Visual Basic are supported, for consistency in naming variables, a choice is made between (1) ruling against the use of case sensitivity in C# code; or (2) prefixing variables—in C# and VB code—with an underscore.

C H A P T E R 2

■ ■ ■

Code Structure

In this chapter I discuss structuring code and note that .NET has three levels of code structure: assembly; namespace, and complex types. We can choose an assembly to structure specialist functionality (e.g., security code) or structure functionality within a hierarchy of nested namespaces or structure functionality in an interface; struct; class; partial class; or generic type. The choices that we make impact not only accessibility to our code, but they also impact the flexibility and maintainability of the code; and the larger the application, the greater the impact!

Assembly

An assembly is used to control the way functionality is accessed and distributed.

What

An assembly is a repository that is used to store related functionality. There are two types of assemblies: an executable (EXE) and a dynamic link library (DLL).

Where

An assembly is used where there is a need to partition or encapsulate functionality into a logical unit.

Why

An assembly can be used to control the way that code is made accessible or distributed to a client. For example, code distributed in an EXE assembly is accessible indirectly through its functionality, whereas code that is in a DLL assembly is accessible directly through its interface.

How

If we use our copy of Visual Studio 2005 as an example, we can see how an assembly is leveraged to structure functionality. In the object browser we see that the core library functionality (mscorlib.dll) is structured in a DLL assembly, as is the security functionality (System.Security.dll). However, Visual Studio 2005 itself is structured in an EXE assembly (devenv.exe), which illustrates how the code designers have used respective code structures

29

30 C H A P T E R 2 C O D E S T R U C T U R E

to prepare code for different roles. As we know, assemblies are generally created as a Visual Studio project type, although they may be created on the command line.

The Standard: Assembly

The standard acknowledges that an assembly may be used to partition specialized functionality and to control distribution and accessibility to that functionality. The choices made to structure code impact not only accessibility to code but also the flexibility and maintainability of the code.

Namespace

A namespace resides in an assembly, and it is used as a tool to structure code.

What

A namespace is a compilation unit in which code can be structured. Implicitly, the visibility of a namespace is public and its access modifier cannot be changed. An assembly may include multiple namespaces where namespaces are commonly embedded in a hierarchy to enable granular or strategic referencing of code.

Where

A namespace is used where there is a requirement to structure functionality within logical units.

Why

Code is more manageable when it is categorized into units of logically related functionality. Namespaces may also be used to avoid conflict between classes or variables with the same names (e.g., ThisNamespace.Class1 and ThatNamespace.Class1).

How

Namespaces are coded by using the namespace keyword followed by a block consisting of opening and closing braces. Namespaces may be nested; the following example illustrates the nesting of the EngineParts namespace within the Inventory namespace. The Piston class may be referenced as Inventory.EngineParts.Piston.—it is accessible or visible within the EngineParts namespace and not immediately within the Inventory namespace:

namespace Inventory

{

namespace EngineParts

{

class Piston { ...}

}

}

C H A P T E R 2 C O D E S T R U C T U R E

31

The Standard: Namespace

The standard acknowledges the use of namespaces and embedded namespaces to strategically structure code and to avoid naming conflicts.

Interface Type

An interface type offers flexibility in the way that code can be structured because of its support of multiple inheritance, it can be implemented at any level in a class hierarchy or in another interface hierarchy.

What

An interface type is a complex reference type that may contain properties, methods, events, and indexers. It exposes an interface without committing the derived type to an implementation. It supports multiple inheritance (implementation inheritance), unlike a class (in .NET) that supports single class inheritance. It may be inherited by a class, a struct, or by another interface type: Its role is structural and polymorphic—not code reuse.

Where

An interface type is used to enhance the interface of a class or struct—it is commonly used to signify that a class or struct performs a given role, which is usually indicated in the name of the interface, such as IDisposable or IBinarySerialize. As it can be inherited anywhere in a class hierarchy, it can be used to enhance a design when it is most appropriate or convenient.

Why

In complex domains, the interface type overcomes the limitations of single class inheritance and offers the opportunity to treat classes that are not part of the same class hierarchy as if they were, by using polymorphism. A class designer may use an interface type to avoid having to reengineer a base class or to enhance its interface through interface inheritance, particularly when features of the interface are optional. For example, the concepts of sedan and tourer can be treated as an embellishment to the car base class, rather than as an attribute of car. The use of an interface type adds flexibility; for example, when new car concepts are introduced (e.g., station wagon or convertible), they can be simply implemented where convenient rather than having to disturb the base class or class hierarchy.

How

An interface type is defined as follows:

namespace ModelT.Interfaces

{

interface ISedan

{

int Doors {get; set;}

32 C H A P T E R 2 C O D E S T R U C T U R E

void DoSomething();

}

interface ITourer

{

int Doors {get; set;} void DoSomethingElse();

}

}

By using an interface type, we can keep the definition of car generic and inherit the appropriate functionality using interface inheritance, as in the following example:

using System;

using ModelT.Interfaces; //reference namespace

namespace ModelTInterfaceExample

{

class Car: ISedan //inherit Sedan functionality

{

int _door;

//implement property public int Door

{

get {return _door;} set {_door = value;}

}

//implement method

public void DoSomething() {;}

}

}

From the previous code snippet, we can see the definition of interface types and the subsequent use of them by a car type to embellish its interface with the interface of a sedan. Class objects instantiated from this class may now be treated polymorphically as Car or Sedan type.

Although an interface type requires that its interface is implemented, by an inheriting class or struct, this may be inconvenient; where only part of the interface type is required by a class or struct, the unwanted part of the interface may be implemented as a stub. For example, an inheriting class may implement a method without functionality, as shown here:

public void DoSomething()

{

; //code stub

}

C H A P T E R 2 C O D E S T R U C T U R E

33

The Standard: Interface Type

The standard acknowledges that an interface type may be used to add flexibility to the way that code is structured. It is commonly used to signify that a class or struct performs a given role or to leverage its ability to support multiple inheritance.

struct Type

A struct is a lightweight alternative to a class and can be used to structure functionality without incurring the overhead penalty of a reference type.

What

A struct is a complex value type that may contain constructors, fields, properties, methods, nested types, operators, and indexers. A struct does not support inheritance itself (unlike a class or interface type), but it may inherit from an interface type.

Where

A struct is used where there is a requirement for a lightweight complex type that isn’t required to support class-inheritance or reference or instantiation semantics. For example, we could use a struct type as a base type for a Car and specialize functionality through interface inheritance. That would be useful in a situation where memory resource allocation is critical (i.e., a program that has to run on a mobile device)—each active instance of a Car would consume less memory if it was built as a struct rather than as a class type. Why? Because the struct is a value type, it is more efficient because it resides on the stack and requires less memory than a class, which is a complex type and resides on the heap.

How

The following code snippet illustrates the definition of a struct type, which inherits the ISedan interface type.

struct myCar: ISedan

{

int _door;

//implement property public int Door

{

get {return _door;} set {_door = value;}

}

//implement method

public void DoSomething() {;}

}

34 C H A P T E R 2 C O D E S T R U C T U R E

If we compare the code structure of a sedan car defined by using the class and struct types, we see that they are identical. However, the sedan car built with the struct type is more resource efficient: it doesn’t have to be instantiated, and it doesn’t have the overhead of a reference type. It is a worthwhile alternative to a class when class inheritance is not required.

The Standard: struct Type

The standard acknowledges a struct type may be used as a lightweight alternative to a class to structure code and leverage interface inheritance in situations where memory allocation is scarce or class-inheritance and referencing are not required.

Class Type

A class is the most sophisticated type used to structure functionality; it supports class inheritance and can be coded as an abstraction or as an implementation.

What

A class, which is a complex reference type, is the definition of an object. Once instantiated, the class is known as a concrete class or object. It may be modified as abstract, which prevents it from being instantiated, or it may be modified as sealed, preventing it from being extended (i.e., inherited). It supports single class inheritance and multiple interface inheritance.

Where

A class is used where there is a requirement to support class-inheritance or instantiation semantics, and the overhead of a reference type is not an issue. For example, we use a class type as a base type where the benefits of inheriting functionality outweigh the additional memory cost of supporting a reference type.

Why

A class is the richest data type in .NET through which all aspects of object-oriented design and development are accessible (abstraction, encapsulation, inheritance, and polymorphism).

How

A class is defined, and then it may be instantiated into an object. However, it need not be instantiated to access functionality if a member is modified as static. It may be extended through class or interface inheritance. The following is an example of a class structure:

class myCar: ISedan

{

int _door;

//implement property public int Door

C H A P T E R 2 C O D E S T R U C T U R E

35

{

get {return _door;} set {_door = value;}

}

//implement method

public void DoSomething() {;}

//class constructor public myCar () {;}

}

The Standard: Class Type

The standard acknowledges the use of a class type where there is a requirement to support class-inheritance or reference semantics and the overhead of a reference type is not an issue.

Partial Type (Introduced C# 2.0)

What

A partial type is a type that is permitted to use the partial modifier. There are three types that may use the partial modifier: class, struct, and interface. Note that the partial modifier is not permitted on the delegate class, however.

Where

A partial type is used where there is a requirement to split a type over multiple files. A consequence of modifying a type as partial is that once the type is compiled, it cannot be extended.

Why

A partial type enables simultaneous development of different aspects of a type in different files. Splitting development is convenient when team members have special skills; for example, one developer may develop the properties that map a user interface, in one file, while another developer may develop complex functionality in methods that reside in another file. Or method development may be split between developers and files.

How

The type is modified with the partial modifier, and all parts must be declared with the partial modifier and reside in the same namespace. Note that a partial type may be nested. The following trivial example illustrates the concept of a partial type. Functionality for MyCar class is

Соседние файлы в предмете Программирование на C++