Value Type Usage Guidelines
A value type describes a value that is represented as a sequence of bits stored on the stack. For a description of all the .NET Framework's built-in data types, see Value Types. This section provides guidelines for using the structure (struct) and enumeration (enum) value types.
Struct Usage Guidelines
It is recommended that you use a struct for types that meet any of the following criteria:
- Act like primitive types.
- Have an instance size under 16 bytes.
- Are immutable.
- Value semantics are desirable.
The following example shows a correctly defined structure.
Public Structure Int32
Implements IFormattable
Implements IComparable
Public Const MinValue As Integer = -2147483648
Public Const MaxValue As Integer = 2147483647
Private intValue As Integer
Overloads Public Shared Function ToString(i As Integer) As String
' Insert code here.
End Function
Overloads Public Function ToString(ByVal format As String, ByVal
formatProvider As IFormatProvider) As String Implements
IFormattable.ToString
' Insert code here.
End Function
Overloads Public Overrides Function ToString() As String
' Insert code here.
End Function
Public Shared Function Parse(s As String) As Integer
' Insert code here.
Return 0
End Function
Public Overrides Function GetHashCode() As Integer
' Insert code here.
Return 0
End Function
Public Overrides Overloads Function Equals(obj As Object) As Boolean
' Insert code here.
Return False
End Function
Public Function CompareTo(obj As Object) As Integer Implements
IComparable.CompareTo
' Insert code here.
Return 0
End Function
End Structure
[C#]
public struct Int32: IComparable, IFormattable
{
public const int MinValue = -2147483648;
public const int MaxValue = 2147483647;
public static string ToString(int i)
{
// Insert code here.
}
public string ToString(string format, IFormatProvider formatProvider)
{
// Insert code here.
}
public override string ToString()
{
// Insert code here.
}
public static int Parse(string s)
{
// Insert code here.
return 0;
}
public override int GetHashCode()
{
// Insert code here.
return 0;
}
public override bool Equals(object obj)
{
// Insert code here.
return false;
}
public int CompareTo(object obj)
{
// Insert code here.
return 0;
}
}
- Do not provide a default constructor for a struct. Note that C# does not allow a struct to have a default constructor. The runtime inserts a constructor that initializes all the values to a zero state. This allows arrays of structs to be created without running the constructor on each instance. Do not make a struct dependent on a constructor being called for each instance. Instances of structs can be created with a zero value without running a constructor. You should also design a struct for a state where all instance data is set to zero, false, or null (as appropriate) to be valid.
Enum Usage Guidelines
The following rules outline the usage guidelines for enumerations:
Do not use an
Enum
suffix on enum types.Use an enum to strongly type parameters, properties, and return types. Always define enumerated values using an enum if they are used in a parameter or property. This allows development tools to know the possible values for a property or parameter. The following example shows how to define an enum type.
Public Enum FileMode Append Create CreateNew Open OpenOrCreate Truncate End Enum [C#] public enum FileMode { Append, Create, CreateNew, Open, OpenOrCreate, Truncate }
The following example shows the constructor for a FileStream object that uses the FileMode enumeration.
Public Sub New(ByVal path As String, ByVal mode As FileMode); [C#] public FileStream(string path, FileMode mode);
Use an enum instead of static final constants.
Do not use an enum for open sets (such as the operating system version).
Use the System.FlagsAttribute Class to create custom attribute for an enum only if a bitwise OR operation is to be performed on the numeric values. Use powers of two for the enum values so that they can be easily combined. This attribute is applied in the following code example.
<Flags()> Public Enum WatcherChangeTypes Created = 1 Deleted = 2 Changed = 4 Renamed = 8 All = Created Or Deleted Or Changed Or Renamed End Enum [C#] [Flags()] public enum WatcherChangeTypes { Created = 1, Deleted = 2, Changed = 4, Renamed = 8, All = Created | Deleted | Changed | Renamed };
**Note **An exception to this rule is when encapsulating a Win32 API. It is common to have internal definitions that come from a Win32 header. You can leave these with the Win32 casing, which is usually all capital letters.
Consider providing named constants for commonly used combinations of flags. Using the bitwise OR is an advanced concept and should not be required for simple tasks. This is illustrated in the following example of an enumeration.
<Flags()> _ Public Enum FileAccess Read = 1 Write = 2 ReadWrite = Read Or Write End Enum [C#] [Flags()] public enum FileAccess { Read = 1, Write = 2, ReadWrite = Read | Write, }
Use type Int32 as the underlying type of an enum unless either of the following is true:
- The enum represents flags and there are currently more than 32 flags, or the enum might grow to have many flags in the future.
- The type needs to be different from int for backward compatibility.
Do not assume that enum arguments will be in the defined range. It is valid to cast any integer value into an enum even if the value is not defined in the enum. Perform argument validation as illustrated in the following code example.
Public Sub SetColor(newColor As Color) If Not [Enum].IsDefined(GetType(Color), newColor) Then Throw New ArgumentOutOfRangeException() End If End Sub [C#] public void SetColor (Color color) { if (!Enum.IsDefined (typeof(Color), color) throw new ArgumentOutOfRangeException(); }
See Also
Design Guidelines for Class Library Developers | Enumeration Type Naming Guidelines | Value Types | Enumerations