An interface defines the signatures for a set of members that implementers must provide. Interfaces cannot provide implementation details for the members. For example, the ICollection interface defines members related to working with collections. Every class that implements the interface must supply the implementation details for theses members. Classes can implement multiple interfaces.
Classes define both member signatures and implementation details for each member. Abstract (MustInherit in Visual Basic) classes can behave like interfaces or regular classes in that they can define members, and they can provide implementation details but are not required to do so. If an abstract class does not provide implementation details, concrete classes that inherit from the abstract class are required to provide the implementation.
While both abstract classes and interfaces support separating contract from implementation, interfaces cannot specify new members in later versions while abstract classes can add members as needed to support additional functionality.
Do favor defining classes over interfaces.
In later versions of your library, you can safely add new members to classes; you cannot add members to interfaces without breaking existing code.
Do use abstract (MustInherit in Visual Basic) classes instead of interfaces to decouple the contract from implementations.
Do define an interface if you need to provide a polymorphic hierarchy of value types.
Value types must inherit from ValueType, and can inherit only from ValueType, so they cannot use classes to separate contract and implementation. In this case, you must use an interface if your value types require polymorphic behavior.
Consider defining interfaces to achieve an effect similar to that of multiple inheritance.
If a type must implement multiple contracts, or the contract is applicable to a wide variety of types, use an interface. For example, IDisposable is implemented by types used in many different scenarios. Requiring classes to inherit from a base class to be disposable would make the class hierarchy too inflexible. Classes such as MemoryStream, which should inherit their stream-based contracts from their parent classes, would not be able to do so and also be disposable.
Monday, May 4, 2009
Design Guidelines - Classes& Structures
Classes are reference types and structures are value types. Reference types are allocated on the heap, and memory management is handled by the garbage collector. Value types are allocated on the stack or inline and are deallocated when they go out of scope. In general, value types are cheaper to allocate and deallocate. However, if they are used in scenarios that require a significant amount of boxing and unboxing, they perform poorly as compared to reference types.
Consider defining a structure instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
Do not define a structure unless the type has all of the following characteristics:
It logically represents a single value, similar to primitive types (integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
If one or more of these conditions are not met, create a reference type instead of a structure. Failure to adhere to this guideline can negatively impact performance.
Consider defining a structure instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
Do not define a structure unless the type has all of the following characteristics:
It logically represents a single value, similar to primitive types (integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
If one or more of these conditions are not met, create a reference type instead of a structure. Failure to adhere to this guideline can negatively impact performance.
Design Guidelines - Types & Namespaces
Do use namespaces to organize types into a hierarchy of related feature areas.
Avoid very deep namespace hierarchies. Such hierarchies are difficult to browse as the user has to backtrack often.
Avoid having too many namespaces.
Types that are used in the same scenarios should be in the same namespaces when possible. Users should not have to import many namespaces to develop common scenarios.
Avoid having types designed for advanced scenarios in the same namespace as types intended for common programming tasks.
In general, you should place advanced types in a namespace within the general namespace, and use Advanced as last identifier in the name. For example, the commonly used types related to XML serialization are in the System.Xml.Serialization namespace and the advanced types are in the System.Xml.Serialization.Advanced namespace.
Do not define types without specifying their namespaces.
Types that are not assigned a namespace are placed in the global namespace. Because they are not in a feature-specific namespace, types in the global namespace are difficult to find using development tools. Additionally, name collisions in the global namespace cannot be resolved
Avoid very deep namespace hierarchies. Such hierarchies are difficult to browse as the user has to backtrack often.
Avoid having too many namespaces.
Types that are used in the same scenarios should be in the same namespaces when possible. Users should not have to import many namespaces to develop common scenarios.
Avoid having types designed for advanced scenarios in the same namespace as types intended for common programming tasks.
In general, you should place advanced types in a namespace within the general namespace, and use Advanced as last identifier in the name. For example, the commonly used types related to XML serialization are in the System.Xml.Serialization namespace and the advanced types are in the System.Xml.Serialization.Advanced namespace.
Do not define types without specifying their namespaces.
Types that are not assigned a namespace are placed in the global namespace. Because they are not in a feature-specific namespace, types in the global namespace are difficult to find using development tools. Additionally, name collisions in the global namespace cannot be resolved
Design Guidelines - Naming Guidelines
Capitalization Conventions:
Pascal Casing
The first letter in the identifier and the first letter of each subsequent concatenated word are capitalized. You can use Pascal case for identifiers of three or more characters. For example:
BackColor
Camel Casing
The first letter of an identifier is lowercase and the first letter of each subsequent concatenated word is capitalized. For example:
backColor
Uppercase
All letters in the identifier are capitalized. For example:
IO
Capitalization Rules for Identifiers
When an identifier consists of multiple words, do not use separators, such as underscores ("_") or hyphens ("-"), between words. Instead, use casing to indicate the beginning of each word.
The following guidelines provide the general rules for identifiers.
Do use Pascal casing for all public member, type, and namespace names consisting of multiple words.
Note that this rule does not apply to instance fields
Do use camel casing for parameter names.
Do not assume that all programming languages are case-sensitive. They are not. Names cannot differ by case alone.
Pascal Casing
The first letter in the identifier and the first letter of each subsequent concatenated word are capitalized. You can use Pascal case for identifiers of three or more characters. For example:
BackColor
Camel Casing
The first letter of an identifier is lowercase and the first letter of each subsequent concatenated word is capitalized. For example:
backColor
Uppercase
All letters in the identifier are capitalized. For example:
IO
Capitalization Rules for Identifiers
When an identifier consists of multiple words, do not use separators, such as underscores ("_") or hyphens ("-"), between words. Instead, use casing to indicate the beginning of each word.
The following guidelines provide the general rules for identifiers.
Do use Pascal casing for all public member, type, and namespace names consisting of multiple words.
Note that this rule does not apply to instance fields
Do use camel casing for parameter names.
Do not assume that all programming languages are case-sensitive. They are not. Names cannot differ by case alone.
Subscribe to:
Posts (Atom)