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