The. NET design Specification, chapter 9th: Common Design Patterns

Source: Internet
Author: User

9th: Common Design Patterns 9.1 aggregation components

Consider providing aggregation components for commonly used attribute domains.

The aggregation component is used to model the concept of a high-level (physical object), rather than to model the system-level tasks.

To make the name of the aggregation component correspond to well-known system entities, such as MessageQueue, Process, or EventLog, you can make the type more compelling.

To make the initialization as simple as possible when designing the aggregation component, the user can use the component only with simple initialization. If an item initialization is required, the exception that is thrown because there is no initialization of the component should explicitly tell the user what to do.

Do not require users of the aggregation component to explicitly instantiate multiple objects in a scene.

Make sure that the aggregation component supports the Create-set-call usage pattern so that the user can instantiate the component, set its properties, and finally invoke some simple methods to implement most of the scenarios.

To provide a default constructor or a very simple constructor for all aggregation components.

To provide a read-write property for an aggregation component, correspond to all parameters in the constructor.

To use events in an aggregation component, do not use a delegate-based API.

Consider using events instead of virtual members that need to be overwritten.

Do not require users of the aggregation component to use inheritance, overriding methods, and implementing interfaces in common scenarios.

Do not require users of the aggregation component to do other work in common scenarios, in addition to writing code. For example, you should not let users configure components with configuration files, or let users generate resource files, and so on.

Consider allowing the aggregation component to automatically switch states.

Do not involve factor types that have multiple states.

Consider integrating the aggregation components into the VS designer.

Consider separating the aggregation components from the factor types and placing them in different assemblies.

Consider exposing the factor types inside the aggregation component to outside access.

9.2 Async Mode

To implement an event-based Async pattern-if the type is a component that supports a visual designer (that is, the type implements IComponent).

To implement the classic Async pattern-If a wait handle must be supported.

Consider using the event-based Async pattern when implementing a high-level API. For example, the aggregation component should implement the pattern.

Consider using the classic Async pattern when implementing the underlying API, in which case more powerful features, less memory consumption, better flexibility, and less disk usage are more important than availability.

Avoid implementing both Async patterns in the same type or even in a set of related types.

To define an API for an asynchronous operation, follow the conventions below. For a synchronous method named operation, a method named Beginoperation and endoperation should be provided, with the method signature shown below (note that the output parameter is not required).

To ensure that the return type of the Begin method implements the IAsyncResult interface.

To ensure that the parameters passed by value and by reference of a synchronous method are passed by value in the Begin method. The output parameters of the synchronization method should not appear in the signature of the Begin method.

Make sure that the return type of the End method is the same as the return type of the synchronous method.

To ensure that any output parameters of the synchronous method and parameters passed by reference are the output parameters of the End method. The parameters placed in the synchronization method should not appear in the signature of the End method.

Do not continue to perform asynchronous operations-if the Begin method throws an exception.

To notify the caller that an asynchronous operation has completed at once by using the following mechanism.

Set iasyncresult.iscompleted to True.

Activates the wait handle returned by the IAsyncResult.AsyncWaitHandle.

Invokes an asynchronous callback function.

To indicate that an asynchronous operation cannot be completed successfully by throwing an exception from the End method.

To synchronize all unfinished operations when the End method is called:

Consider throwing InvalidOperationException exceptions-if the user calls the End method two times with the same IAsyncResult, or IAsyncResult is returned from another unrelated Begin method.

Set iasyncresult.completedsynchronously to true-when and only if the asynchronous callback function will run in the thread that called the Begin method.

Be sure to invoke the event handler in the correct thread. This is one of the main benefits of using the event-based async pattern compared to the classic async mode.

To make sure that either the operation is complete, the operation is faulted, or the operation is canceled, the event handler is called. You should not let your application wait indefinitely for an event that never happens.

To ensure that the properties of the access time parameter class throw an exception after the asynchronous operation fails. In other words, if an error causes the operation to fail, then the user should not be allowed to access the result of the operation.

Do not define a new event handler or event argument type for a method that returns a null value. To use Asynccompletedeventargs,asynccompletedeventhandler or eventhandler<asynccompletedeventarg>.

To ensure that if the Paogresschanged event is implemented in one step, no more such events should occur after the completion event of the operation has been triggered.

To ensure that the standard ProgressChangedEventArgs is used, the progresspercentage can always be used to represent the percentage of progress (not necessarily completely accurate, but expressed as a percentage). If you are not using standard progress, it would be more appropriate to derive a subclass from ProgressChangedEventArgs, in which case you should keep progresspercentage to 0;

To start the ProgressChanged event when there is a need to report incremental results.

To extend the ProgressChangedEventArgs to save the incremental result data, define the ProgressChanged event with the extended time parameter class.

To separate the incremental results report from the progress report.

To define a separate <methodname>progreesschanged event and corresponding event argument class for each asynchronous operation, process the incremental result data for the operation.

  

9.3 Dependency Properties

To provide dependency properties-if you need them to support a variety of WPF features, such as styles, triggers, data bindings, animations, dynamic resources, and inheritance.

To inherit from DependencyObject or its subtypes when designing a dependency property. The property store implemented by this type is highly efficient, and it also automatically supports data binding for WPF.

To provide a general CLR property for each dependency property and a public static read-only field that holds the System.Windows.DependencyProperty instance.

To implement a dependency property by calling Dependencyobject.getvalue and Dependencyobject.setvalue.

To name a static field of a dependency property, add a "property" suffix to the name of the dependency attribute.

Do not explicitly set the default value of a dependency property in your code, and you should set the default value in the metadata.

Instead of adding extra code to the accessor of a property, you should use standard code to access the static field.

Do not use dependency properties to store confidential data. Any code can access the dependent properties, even if they are private.

Instead of putting the validation logic of the dependency property in the accessor, you should pass the validation destroy function to the Dependencyproperty.register method.

Instead of implementing notification of property changes in the accessor of a dependency property, you should register the callback function that changes the notification to PropertyMetadata, which is an attribute provided by the dependency property itself, which must be used in order to support change notification.

Instead of implementing property-forcing assignment logic in the accessor of a dependency property, you should register a mandatory-assignment callback function with PropertyMetadata. The latter is an attribute provided by the dependency property itself, which must be used in order to support mandatory assignment.

  

9.4 disopse Mode

To implement the basic Dispose pattern for a type that contains instances of a disposed type.

To implement the basic Dispose pattern for a type and provide an finalization method-if the type holds a type that needs to be explicitly freed by the developer, and the latter itself does not have an finalization method.

Consider implementing the basic Dispose pattern for a class-If the class itself does not hold an unmanaged resource or a disposable object, but its subtypes may hold unmanaged resources or disposable objects.

To implement the IDisposable interface as follows, call Dispose (true) before invoking the GC. SuppressFinalize (This).

Do not define a no-parameter Dispose method as a virtual method.

Do not declare any other overloaded methods other than Dispose () and Dispose (bool) for the Dispose method.

To allow multiple calls to the Dispose (bool) method. He can do nothing after the first call.

Avoid throwing exceptions from the Dispose (bool) method, except in the case of an emergency, where the process has been compromised (such as leaks, shared state inconsistencies, and so on).

To throw a ObjectDisposedException exception from a member-if the member cannot continue to use after the object is terminated.

Consider providing a close () method outside of the Dispose () method-if Close is a standard term in the realm.

Avoid defining a type that can be terminated.

Do not define a value type that can be terminated.

To define a type as a type that can be finalized-if the type is responsible for releasing the unmanaged resource, and the unmanaged resource itself does not have an finalization method.

To implement the basic Dispose pattern for all of the possible types of finalization.

Do not access any of the finalization objects in the finalization method, there is a great risk that the object being accessed may have been terminated.

To define a Finalize method as protected.

Do not leave out any exceptions in the finalization method, unless it is a fatal system error.

Consider creating a predictable object for emergencies-if the finalization method is mandatory when the application domain is forcibly unloaded or the thread exits unexpectedly.

9.5 Factory Mode

The constructor is preferred instead of the factory, because constructors are generally easier to use, more consistent, and more convenient than a special object construction mechanism.

Consider using the factory-if the constructor provides an object creation mechanism that does not meet the requirements.

To use the factory-if the developer may not be aware of the exact type of object to be created, such as programming to a base class or interface is the case.

Consider using the factory method-if this is the only way to make the operation self-explanatory.

To use factory in a transform-style operation.

To try to implement the factory operation method as a method, rather than as a property.

The newly created object instance is returned by the return value of the method instead of the method's output parameter.

Consider connecting create with the type name you want to create and naming the factory method one at a time.

Consider connecting the type name you want to create with Factory to name the factory type at a time. For example, consider naming the factory type that created the Control object as Controlfactory.

  

9.6 Support for LINQ

To implement IENUMERABL<T>, the purpose is to get basic LINQ support.

Consider implementing Icollection<t>, which is designed to improve the performance of queries.

Consider implementing Iqueryable<t>-if you have to access a query expression that is passed to a member of IQueryable.

Don't be hasty in implementing IQUERYABLE<T> Understand how this might affect performance.

To throw NotSupportedException in the Iqueryable<t> method-if the operation is not supported on your data source.

To implement the Query pattern as an instance method in a new type-if you are outside of LINQ, these methods still have a meaning in the type. Otherwise, they should be implemented as extension methods.

To make the implementation of the Query pattern implemented in the type ienumerable<t>.

Consider that when you design LINQ operators, let them return the domain-specific enumerable types. Although in essence, the Select Query method can return any type, you usually want the result of the query to be an enumerable type.

Avoid implementing only part of the Query pattern-if you do not want to fall back to the basic ienuerable<t> implementation.

To define a separate type for an ordered sequence, separate it from the corresponding unordered sequence. Such a type should define the ThenBy method.

To defer the actual query operation. For most members of the query pattern, I want them to just create a new object and generate the elements of the collection's heavy-load query condition at enumeration time.

The extension method that is used for the query is placed in a child namespace named "Linq" in the primary namespace. For example, the extension method defined for the System.Data attribute is placed in the System.Data.Linq namespace.

To use Expression<func<...>> in parameters, instead of func<...>-if you need to query the query expression.

9.7 Optional Feature Mode

Consider using the Optional Feature pattern for optional attributes in abstractions.

To provide a simple Boolean property to let the user detect whether an object supports optional attributes.

To define an optional attribute as a virtual method in the accumulation, and throw a NotSupportedException exception in the method.

  

9.8 Simulated convariance mode

Consider using simulated convariance mode-if you need a uniform type to represent all instances of a generic type.

Be sure to implement the base type members and the corresponding generic type members in an equivalent manner.

Consider using an abstract base class to represent the root type, rather than using an interface to represent the root type.

Consider using a non-generic type as the base type-if such a type already exists.

  

9.9 Template Method Mode

Avoid defining a public member as a virtual member.

Consider using the Template Method mode for better control of extensibility.

Consider the non-show member name plus the "Core" suffix as the name, to name a protected virtual member that provides an extension point for that fee virtual member.

  

9.10 Timeouts

Priority is given to the user to set the timeout length through the parameters.

A TimeSpan is preferred to represent the time-out length.

To throw a system.timeoutexception exception after a timeout.

Do not tell the user that a timeout has occurred by returning an error code.

  

9.11 types available for use in XAML

Consider providing a default constructor-if you want the type to be used in XAML.

To provide markup extensions-if you want the XAML reader to be able to create immutable types:

Avoid defining a new type converter, unless the conversion is natural and intuitive. In general, you should limit the use of type converters to places in the. NET framework that already use type converters.

Consider using Contentpropertyattribute for the most commonly used properties, resulting in more convenient XAML syntax.

The. NET design Specification, chapter 9th: Common Design Patterns

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.