. NET design specification ———— Type design specification

Source: Internet
Author: User
Tags protected constructor

Type Design Specifications

From the perspective of the CLR, there are only two types of value and reference types, but from the perspective of frame design we have logically divided the types into more groups. As shown below:

Class is the general case of reference types, which account for most of the situation in the framework, the popularity of the class is attributed to its support for object-oriented features, and its universal applicability, base classes and abstract classes are two special logical groupings, which are related to extensibility.

Because the CLR does not support multiple inheritance, an interface type can be used to simulate multiple inheritance, either by a reference type or by a value type.

Structs are general cases of value types and should be used for small, simple types, just like the basic types of programming languages.

An enumeration is a special case of a value type that is used to define a small group of values.

Static classes are types that are used to accommodate static members and are commonly used to provide quick access to other operations.

Delegates, exceptions, Attribute, data, and collections are special cases of reference types, each of which has its own purpose.

1.1 Types and namespaces

Before designing a large framework, you should decide how to divide functionality into a set of functional domains, which are represented by namespaces, to ensure that a set of organized namespaces contains a well-integrated, non-conflicting, and not repetitive, top-down design is necessary. resulted in the following specification:

to use namespaces to organize the types into a hierarchical structure of related domain attributes. (mainly to organize types into a structured, easy-to-navigate, easy-to-understand hierarchy)

avoid very deep namespace hierarchies (difficult to navigate and require frequent backtracking)

Avoid having too many namespaces.

avoid placing types that are designed for high-level scenes and common programming tasks in the same namespace. (easy to understand the basic concepts of the framework, easy to use the framework in common scenarios)

do not specify a namespace to define the type. (organize related types into a hierarchy to help resolve possible name collisions)

Naming of standard sub-namespaces

Rarely used types should be placed in the sub-namespace, so as not to disturb the main namespace, we identified a few sets of types that should be separated from the main namespace Central.

1.. Design Child namespaces

The type that is used only for design time should be placed in the name. Design's sub-namespace. such as: System.Windows.Forms.Design;

System.Messaging.Design;

To use the belt. Design suffix namespaces to accommodate the types of functionality that are provided for the basic namespace.

2.. Permissions Sub-namespaces

The license type should be placed in the name ". Permissions "in the sub-namespace.

To use the belt. Permissions "suffix namespace to accommodate those types of basic namespaces that provide custom permissions.

3.. Interop Sub-namespaces

Many frameworks need to support interoperability with legacy systems (interoperability).

To use the belt. Interop "suffix namespaces to accommodate types that provide interoperability functions for basic namespaces.

To use the belt. Interop "suffix namespace to accommodate all code that resides in the PIA.

1.2 Choice between class and structure

The reference type is allocated on the heap, managed by the garbage collector, and the value type is either allocated on the stack and released when the stack is expanded, or inline in the type that holds it and released when the type that holds it is freed. Therefore, the allocation and deallocation of value types is less expensive than the allocation and deallocation of reference types.

An array of reference types is not a non-inline assignment, meaning an array element is simply a reference to an instance of a reference type that is located in the heap. The allocation of a value type is inline, and the element of the array is the true instance of the value type. Therefore, the allocation and deallocation of value types is much more expensive than the reference type, and in most cases the array of value types has better locality.

Value types are coerced into objects or boxing because boxing and objects are allocated on the heap and are managed by the garbage collector, so too many unboxing operations affect the heap, the garbage collector, and the system performance.

The assignment of a reference type is a copy reference, while the assignment of a value type copies the entire value, which is much smaller than the ratio type for large reference type replication overhead.

A reference type is a reference pass, and a value type is a value pass. Changing one instance of a reference type affects other instances, changing the instance of a value type without affecting its copy.

Most types in a framework should be classes, but in some special cases, the use of structures is more appropriate because of the characteristics of value types.

Consider defining a struct rather than a class ( if the type's instances are small, the life cycle is shorter and often embedded in other objects )

Do not define a structure unless the type has the following characteristics:

It logically represents a separate value, similar to the basic type (int)

Its instance size is less than 16 bytes

It's immutable.

It does not need to be boxed regularly

In all other cases, the type should be defined as a class.

1.3 Selection between classes and interfaces

In general, a class is a preferred choice for the abstraction of a burst.

The point is that when you need to allow the API to evolve, it's less flexible than a class, and once you publish an interface, its members are always fixed, and adding anything to the interface destroys the existing types that have already implemented the interface.

class provides more flexibility, you can add members to a published class. As long as the method being added is not abstract, any existing derived classes can continue to be used without changes.

To take precedence over the class rather than the interface

Class-based APIs tend to evolve much more easily than interface-based APIs because members can be added to a type without breaking existing code.

Use an abstract class instead of an interface to decouple the contract from the implementation.

Abstract classes are designed to be able to decouple the contract from the implementation, which is comparable to the degree to which the interface can be reached.

to define an interface, if you need to provide a Polymorphic value type hierarchy. (value types cannot inherit from other types, but they can implement interfaces)

Consider defining an interface to achieve a similar effect to multiple inheritance.

1.4 Design of abstract class

Do not define a public or internal protected constructor in an abstract type.

The constructor parameter for a type is public only if the user needs to create an instance of the type, because you cannot create an instance of an abstract class, so if the abstract type has a public constructor

To define a protected constructor or intrinsic constructor for an abstract class.

A protected constructor is only allowed when a subtype is created, and the base class can do its own initialization.

An internal constructor can be used to restrict the implementation of the abstract class to the assembly that defines the abstract class.

to provide at least one specific type that inherits from this class for the published abstract class.

Helps verify that the abstract class is designed correctly.

1.5 Design of Static class

A static class is defined as a class that contains only static members. If a class is defined as static, it is sealed, abstract, and cannot overwrite or declare any instance members.

Static classes are a trade-off between pure object-oriented design and simplicity, and they are widely used to provide shortcuts for accessing other operations, or to provide some functionality without the need for a complete object-oriented wrapper. (system.enviroment)

to minimize the use of static classes

Static classes are used only as auxiliary classes to support the object-oriented core of the framework.

do not treat static classes as clutter bins.

Every static class should have its definite purpose.

do not declare or overwrite instance members in a static class.

to define a static class as sealed, abstract, and add a private instance constructor.

1.6 Design of the interface

While in most cases the API is best built with classes or structs, in some cases the interface is more appropriate.

The CLR does not support multiple inheritance, but allows a type to implement one or more interfaces, so multiple inheritance is often implemented with interfaces.

When you create a public interface that can be supported for many types, including value types.

to define an interface, if you need a set of types that include value types, support some common APIs.

Consider defining an interface if you need to allow a type that has been inherited from another type to support the functionality provided by that interface.

Avoid using the token interface (interfaces without members)

To provide at least one type that implements the interface for the interface.

To provide at least one API for each interface you define (a method that takes an interface as an argument or a property of a type of that interface)

Do not add members to the published interface.

Doing so destroys the implementation of the interface, and in order to avoid the issue of the version, a new interface should be created.

In general, when designing reusable libraries for managed code, you should choose a class instead of an interface.

1.7 Design of the structure

A common purpose value type is often referred to as a struct (struct).

Do not provide a default constructor for the struct. (C # does not allow structs to have default constructors)

To ensure that all instance data is zero, false, or NULL, the structure is still in a valid state. (You can prevent an invalid instance from being created when a struct is created)

To implement iequatable<t> for a value type

The Object.Equals method of the value type causes boxing, and the default implementation is not efficient because the reflection is used, iequatable<t>. equals performance is much better and does not result in boxing.

do not display the extension System.ValueType

1.8 Design of enumerations

An enumeration is a special type of value that has two types of enumerations: Simple enumeration and Tag enumeration.

A simple enumeration represents a small, closed set of choices. For example (a set of colors):

Public enumcolor{

Red,

Green,

Blue,

......

}

The markup enumeration is designed to support bitwise operations on enumeration values. A common example of a tag enumeration is a selection list

[Flags]

Public Enumattributetargets

{

ASSEMBLY=0X0001,

MODULE=0X0002,

cass=0x0004,

struct=0x0008

}

To use enumerations to strengthen the parameters, properties, and the type of the return value of the collection that represents the value.

Instead of using static constants, use enumerations first. (An enumeration is a structure that contains a set of static constants)

Do not use enumerations for development collections (such as operating system versions, etc.)

Do not provide enumeration values that are reserved for future use.

Avoid displaying an enumeration of only one value for the burst.

Do not include the Sentinel value in the enumeration value.

To provide a 0 value for a simple enumeration type. (It should be considered that the value is nothing, such as none, if such a value is not suitable for a particular enumeration, then the most common default value in the enumeration should be assigned a value of 0)

Consider using Int32 as the basic implementation type of the enumeration.

To name a tag enumeration with a plural noun or noun phrase, use a singular noun or noun phrase to name a simple enumeration.

Do not expand System.Enum directly

Design of 1.8.1 Tag enumeration

To use System.FlagsAttribute for a tag enumeration, do not apply the attribute to a simple enumeration.

[Flags]

Public Enumattributetargets

{

.....

}

Use the power of 2 as the value of the tag enumeration so that they can be combined freely by bitwise or manipulation.

[Flags]

Public Enumwatcherchangetypes

{

CREATED=0X0002,

deleted=0x0004,

changed=0x0008,

renamed=0x00010,

}

Consider providing special enumeration values for common tag combinations. (bit operations are a high-level concept that is not required for simple tasks, FileAccess.ReadWrite is an example of this)

[Flags]

Public enumfileaccess

{

Read=1,

write=2,

readwrite=read| Write,

}

Avoid having a tag enumeration created that contains some invalid combinations.

avoid using zero as the value of the tag enumeration, unless the value indicates "all tokens are cleared" and is appropriately named according to a specification . (CLR specifies the default value for any value type "All bits are clear 0")

To name the 0 value of the tag enumeration "None", the value must always mean "all tokens are cleared" for its index enumeration.

[Flags]

Public Enumborderstyle

{

fixed3d=0x1,

FIXEDSINGLE=0X2,

none=0x0

}

However, the rule applies only to tag enumerations, and for non-tagged enumerations, avoiding the use of 0 values is actually detrimental, and all enumerated types start with zero values.

1.8.2 Adding a value to an enumeration

It is often found that you need to add a value to an enumeration after discovery, and if the newly added value is a return value for an existing API, there is a potential application compatibility issue.

Consider adding a value to an enumeration, despite the risk of a bit of compatibility.

If you have actual data indicating that adding a value to an enumeration can lead to an incompatible application, consider adding a new API to return the old and new enumeration values so that you are still compatible with existing applications.

1.9 Nested types

A nested type is a type that is defined within the scope of another type. Another type is called the outer type. A nested type has access to all members of the outer type. You can access a private field that defines the outer layer type and a protected field that defines all the parent classes of the outer layer type.

In general, as few nested types as possible, nested types are tightly coupled to the outer types and are not suitable for common types. Nested types are suitable for modeling the implementation details of their outer types.

use nested types when you want a type to have access to members of the outer type.

Do not use nested types for logical grouping, and namespaces should be used to achieve this purpose.

Avoid exposing burst nesting types, except if you only need to declare variables of a nested type in a very small number of scenarios, such as derived subclasses, or in other advanced custom scenarios.

Do not use a nested type if the type may be referenced by a type other than its outer type.

Do not use nested types if they need to be instantiated by customer code.

Do not define a nested type as a member of an interface.

In general, use as few nested types as possible, and avoid exposing nested types to the outside world.

. NET design specification ———— Type design specification

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.