.Net Framework Design Guidelines

Member Design

DoTry to use descriptive parameter names to indicate the default used by shorter overloads.
AvoidArbitrarily varying parameter names in overloads.
AvoidBeing inconsistent in the ordering of parameters in overloaded members.
DoMake only the longest overload virtual (if extensibility is required).
Do NotUse ref or out modifiers to overload members.
DoAllow null to be passed for optional arguments.
DoUse member overloading rather than defining members with default arguments.
AvoidImplementing interface members explicitly without having a strong reason to do so.
ConsiderImplementing interface members explicitly, if the members are intended to be called only through the interface.
ConsiderImplementing interface members explicitly to simulate variance (change parameters or return type in “overridden” members).
ConsiderImplementing interface members explicitly to hide a member and add an equivalent member with a better name.
Do NotUse explicit members as a security boundary.
DoProvide a protected virtual member that offers the same functionality as the explicitly implemented member if the functionality is meant to be specialized by derived classes.
ConsiderUsing a property, if the member represents a logical attribute of the type.
DoUse a property, rather than a method, if the value of the property is stored in the process memory and the property would just provide access to the value.
DoUse a method, rather than a property, when the operation: 1. Is an order of magnitude slower than field access. 2. Is a conversion operation (i.e., ToString()). 3. Returns a different result each time it is called (i.e., DateTime.Now()). 4. Has a significant noticeable side effect. 5. Returns a copy of an internal state. 6. Returns an array.
DoCreate get-only properties if the caller should not be able to change the value of the property.
Do NotProvide set-only properties of properties with the setter having broader accessibility than the getter.
DoProvide sensible default values for all properties, ensuring that the defaults do not result in a security hole or terribly inefficient code.
DoAllow properties to be set in any order even if this results in a temporarily invalid state of the object.
DoPreserve the previous value if a property setter throws an exception.
AvoidThrowing exceptions from property getters.
ConsiderUsing indexers to provide access to data stored in an internal array.
ConsiderProviding indexers on types representing collections of items.
AvoidIndexed properties with more than one parameter.
AvoidIndexers with parameter types other than System.Int32, System.Int64, System.String, System.Object, enum, or generic type parameters.
DoUse the name Item for indexed properties unless there is an obviously better name (e.g., see the Chars property on System.String).
Do NotProvide both an indexer and methods that are semantically equivalent.
Do NotProvide more than one family of overloaded indexers in one type.
Do NotUse non default indexed properties.
ConsiderRaising change notification events when property values in high-level APIs (usually designer components) are modified.
ConsiderRaising change notification events when the value of a property changes via external forces.
ConsiderProviding simple, ideally default constructors.
ConsiderUsing a static factory method instead of a constructor if the semantics of the desired operation do not map directly to the construction of a new instance, or if following theconstructor design guidelines feels unnatural.
DoUse constructor parameters as shortcuts for setting main properties.
DoUse the same name for constructor parameters and a property, if the constructor parameters are used to simply set the property.
DoMinimal work in the constructor.
DoThrow exceptions from instance constructors if appropriate.
DoExplicitly declare the public default constructor in classes, if such constructor is required.
AvoidExplicitly defining default constructors on structs.
AvoidCalling virtual members on an object inside its constructor.
DoMake static constructors private.
Do NotThrow exceptions from static constructors.
ConsiderInitializing static fields inline rather than explicitly using static constructors, as the runtime is able to optimize the performance of types that don't have an explicitly defined static constructor.
DoUse the term “raise” for events rather than “fire” or “trigger”.
DoUse System.EventHandler<T> instead of manually creating new delegates to be used as event handlers.
ConsiderUsing a subclass of EventArgs as the event argument, unless you are absolutely sure the event will never need to carry any data to the event handling method, in which case you can use the EventArgs type directly.
DoUse a protected virtual method to raise each event.
DoTake a parameter typed as the event argument class to the protected method that raises an event.
Do NotPass null as the sender when raising a non static event.
Do NotPass null as the event data parameter when raising an event (You should use EventArgs.Empty)
ConsiderRaising events that the end user can cancel.
DoUse a return type of void for event handlers.
DoUse object as the type of the first parameter of the event handler, and call it sender.
DoUse System.EventArgs or its subclass as the type of the second parameter of the event handler, and call it e.
Do NotHave more than two parameters on event handlers.
Do NotProvide instance fields that are public or protected.
DoUse constant fields for constants that will never change.
DoUse public static readonly fields for predefined object instances.
Do NotAssign instances of mutable types to readonly fields.
AvoidDefining operator overloads, except in types that should feel like primitive (built-in) types.
ConsiderDefining operator overloads in a type that should feel like a primitive type.
DoDefine operator overloads in structs that represent numbers (such as System.Decimal).
Do NotBe cute when defining operator overloads.
Do NotProvide operator overloads unless at least one of the operands is of the type defining the overload.
DoOverload operators in a symmetric fashion.
ConsiderProviding methods with friendly names corresponding to each overloaded operator.
Do NotProvide a conversion operator if such conversion is not clearly expected by the end users.
Do NotDefine conversion operators outside of a type's domain.
Do NotProvide an implicit conversion operator if the conversion is potentially lossy.
Do NotThrow exceptions from implicit casts.
DoThrow System.InvalidCastException if a call to a cast operator results in a lossy conversion and the contract of the operator does not allow lossy conversions.
DoUse the least derived parameter type that provides the functionality required by the member.
Do NotUse reserved parameters.
Do NotHave publicly exposed methods that take pointers, arrays of pointers, or multidimensional arrays as parameters.
DoPlace all out parameters following all of the by-value and ref parameters (excluding parameter arrays), even if it results in an inconsistency in parameter ordering between overloads.
DoBe consistent in naming parameters when overriding members or implementing interface members.
DoUse enums if otherwise a member would have two or more Boolean parameters.
Do NotUse Booleans unless you are absolutely sure there will never be a need for more than two values.
ConsiderUsing Booleans for constructor parameters that are truly two state values and are simply used to initialize Boolean properties.
DoValidate arguments passed to public, protected, or explicitly implemented members.
DoThrow ArgumentNullException if a null argument is passed but the member does not support null arguments.
DoValidate enum parameters.
Do NotUse Enum.IsDefined for enum range checks.
DoBe aware that mutable arguments passed might have changed after they were validated.
AvoidUsing out or ref parameters.
Do NotPass reference types by reference.
ConsiderAdding the params keyword to array parameters, if you expect the end users to pass arrays with a small number of elements.
AvoidUsing params arrays if the caller would almost always have the input already in an array.
Do NotUse params arrays if the array is modified by the member taking the params array parameter.
ConsiderUsing the params keyword in a simple overload, even if a more complex overload could not use it.
DoTry to order parameters to make it possible to use the params keyword.
ConsiderProviding special overloads and code paths for calls with a small number of arguments in extremely performance-sensitive APIs.
DoBe aware that null could be passed as a params array argument.
Do NotUse the varargs methods, otherwise known as the ellipsis.
DoProvide an alternative for any member that takes a pointer argument, as pointers are not CLS compliant.
AvoidDoing expensive argument checking of pointer arguments.
DoFollow common pointer-related conventions when designing members with pointers.