Flags Attribute for Enum Types

Problem
You want to know how to define enum types that contain a collection of flags instead of single values.

Solution
Mark them with the Flags attribute.

Comments
These types of enums are usually manipulated using bitwise operators. For example…

Example

using System;

namespace Playground
{
    internal static class Program
    {
        [Flags]
        private enum Colors
        {
            Red = 1,
            Blue = 2,
            Green = 4,
            Yellow = 8
        }

        public static void Main()
        {
            var textRepresentation = (Colors.Blue | Colors.Green).ToString();
            Console.WriteLine(textRepresentation);
            // Output is Blue, Green.
        }
    }
}

Naming Enum Types

Problem
You’re interested in naming guidelines for enum types.

Solution
Follow these rules when assigning names to enums:
1. Assign a singular name if the enum type’s members are never combined with | or + operators.
2. Assign a plural name if the enum type’s members will be combined with | or + operators (bit-coded).
c. Don’t use special suffixes when naming enum types.

Comments
Enter each enum value on its own line.

Examples

public enum Sex {
    Male,
    Female,
    Unknown
}

[Flags()]
public enum Sex {
    Male = 1,
    Female = 2,
    Unknown = 3
}

Types with Nested Enums

Problem
You want to know if it’s acceptable to nest an enum inside another type.

Solution
It’s acceptable if the enum type is used to define arguments or return values in one or more of the type’s methods.

Comments
An example of this technique in the .NET Framework is the System.Environment.SpecialFolder enum. This enum is used only as an argument to the GetFolderPath method of the System.Environment type.

One Source File for Enum Types

Problem
You want to know how to organize your enum types.

Solution
Collect all enum types in a single file and name it Enums.cs.

Comments
Enum definitions are typically short. Placing all of them in a single file is advantageous for a number of reasons. First, it cuts down on the number of files in the solution. Second, it enables you to find what you’re looking for more easily. Finally, there are a couple of exceptions to this rule. One is when it makes sense to place them in different namespaces. Another is when you have enum types nested in other types.

Implementing Interfaces in Structures

Problem
You want to know if it’s permitted to define structures that implement interfaces.

Solution
Steer clear of defining structures that implement interfaces. If you must implement an interface in a structure, don’t assign fields from inside the interface methods.

Comments
The reason for this guideline is that C# boxes a structure when it’s accessed via an interface variable. You want to avoid boxing operations because they add overhead and consume memory.

Example

// Not recommended: If the code in the method modifies a field, the changes aren't propagated to the original structure.
interface IPerson {
    void SetName(string name);
}

struct User : IPerson {
    public string Name;

    // This method modifies a field.
    public void SetName(string name) {
        this.Name = name;
    }
}

class App {
    static void Main() {
        User user = new User();
        Initialize(user, "Jason"); // Hidden box operation.
        Console.WriteLine(user.Name); // Name is still empty!
    }

    static void Initialize(IPerson user, string name) {
        user.SetName(name);
    }
}

Overloading Equals in Value Types

Problem
You want to know how to handle the Equals method when implementing a structure.

Solution
When implementing value types like structures, you’ll want to overload the Equals method. Define both instance and static versions and make them take typed arguments.

Comments
Typed versions of the Equals method improve performance by avoiding boxing. The ValueType.Equals method, which all value types inherit, is inefficient. That’s because the base method uses reflection to compare all fields. Additionally, if you override the Equals method, you should override the GetHashCode method along with the == and != operators.

Example

public struct Point {
    // Properties in a real-world app.
    public readonly double xAxis;
    public readonly double yAxis;

    public Point(double x, double y) {
        this.xAxis = x;
        this.yAxis = y;
    }

    // Strongly-typed version of the instance method.
    public bool Equals(Point point) {
        return this.xAxis == point.xAxis && this.yAxis == point.yAxis;
    }

    // Strongly-typed version of the static method.
    public static bool Equals(Point pointOne, Point pointTwo) {
        return pointOne.xAxis == pointTwo.xAxis && pointOne.yAxis == pointTwo.yAxis;
    }
}

Default State for Structure Members

Problem
You want to know how to handle the default state of members in structures.

Solution
Create structures so that they’re in a valid state when their members are null or zero.

Comments
Defining parameterless constructors in structures is not permitted. It’s also illegal to define initial values for fields in structures. What happens is the CLR zeros out all fields when it creates the structure. As an example, consider a structure with a Boolean field or property. You’ll want to ensure that a false state is a valid initial value for it. Otherwise, you’ll want to rename the field to reverse its meaning.

The Size of Structures

Problem
You need to define a structure. You want to know the ideal size and how to optimize it.

Solution
Define structures that are 16 bytes or smaller. Define them so their size is an integer multiple of 4 bytes. Finally, sort their fields so the CLR doesn’t insert hidden padding bytes to keep elements aligned.

Comments
Collections of structures take a block of contiguous memory. You make the best use of memory on a 32-bit OS when you make their size a multiple of 4 bytes. The CLR arranges the layout of all fields in a class to avoid padding bytes. However, it does not perform this optimization on a structure unless it’s marked with the StructLayout attribute set to LayoutKind.Auto.

Example

/* The wrong way to implement a structure.
** It appears to take 8 bytes, but it actually takes 12.
*/
struct ExampleStruct {
    // This is followed by 3 hidden padding bytes.
    public byte aSingleByte;
    public int aSingleInt;
    // This is followed by a hidden padding type.
    public byte aSecondByte;
    public short aSingleShort;
}

/* The correct way to implement a structure.
** No hidden padding bytes are inserted.
*/
struct ExampleStruct {
    public byte aSingleByte;
    public byte aSecondByte;
    public short aSingleShort;
    public int aSingleInt;
}

Structures With Value Type Members

Problem
You want to create a data structure with a few value type members. How should you proceed?

Solution
Choose a structure in this scenario. This type is ideal when you have a few members, and all are value types.

Comments
This technique proves very effective if you plan on creating arrays of these objects. Structures perform well. They don’t take memory from the managed heap and reduce the number of garbage collections. Arrays of structures take adjacent memory locations. They need only a single memory allocation operation which releases faster. Finally, they perform better because their elements fit into the CPU’s secondary cache.