Enums unter C#
Frank Dzaebel, Quelle:u.a. Artikel über Enums, erstellt am: 21.1.2006, zuletzt geändert:  17.2.2006
Kategorie: Implementation, .NET-Version: 2.0

[Dieser Artikel dient relevanter Code & Informations-Sammlung bzgl. Enums]
- Test-Version completionlist-Hack in C#.
- U.a. Ralf Wesphal's generische "Set"-Klasse. John Skeet's "Enhanced Enums in C#".
- Java 5.0 Enum's: In früheren Versionen von Java war ein Enum wie in C/C++/C# letztlich nur ein int. Genauer, es gab keine Enums! Dies wurde in Java 5.0 geändert. Doch sie haben hier eine weitergehende Semantik, als in .NET.
- Empfohlener Enumerationsentwurf in C#.
- Design Guidelines Update: Enum Design
Completionlist-Hack in C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Globalization;

namespace Enums
{
  #region class WindowPart
  
  /// <completionlist cref="WindowParts"/>
  [TypeConverter(typeof(WindowPartsConverter))]
  public class WindowPart
  {
    private string name;

    public WindowPart(string name)
    {
      this.name = name;
    }

    public string Name
    {
      get { return name; }
      set { name = value; }
    }

    public override string ToString()
    {
      return name;
    }
  }
  #endregion class WindowPart


  #region class WindowParts
  public sealed class WindowParts
  {
    private WindowParts() {}

    public static WindowPart Border
    {
      get { return new WindowPart("Border"); }
    }

    public static WindowPart TitleBar
    {
      get { return new WindowPart("TitleBar");}
    }

    public static WindowPart ClientArea
    {
      get { return new WindowPart("ClientArea"); }
    }
  }
  #endregion class WindowParts


  #region class WindowPartsConverter

  public class WindowPartsConverter : EnumConverter
  {
    public WindowPartsConverter(Type type) : base(type) { }
  
    public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)
    {
      return sourceType == typeof(string);
    }

    public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,object value)
    {
      if (value is String)
        return new WindowPart((string)value);
      else
        throw new ArgumentException("'value' must be of type 'String'.");
    }

    public override bool CanConvertTo(ITypeDescriptorContext context,Type destinationType)
    {
      return destinationType == typeof(WindowPart);
    }

    public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture,object value,Type destinationType)
    {
      return ((WindowPart)value).Name;
    }

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
      return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
      // Bestimmen der gemeinsamen Eigenschaften des Typs "WindowPart".
      List<WindowPart> standardValues = new List<WindowPart>();
      PropertyInfo[] sharedProperties =
        typeof(WindowParts).GetProperties(BindingFlags.Public | BindingFlags.Static);
      foreach (PropertyInfo prop in sharedProperties)
        standardValues.Add((WindowPart)prop.GetValue(typeof(WindowParts),null));
      return new StandardValuesCollection(standardValues);
    }
  }
  #endregion class WindowPartsConverter
}

Ralf Wesphal's generische Set-Klasse:
using System.Collections.Generic;
using System;
using System.Text;

public class Set<TEnum>
{
  #region "Data"
  bool flagsEnum;
  System.Collections.BitArray members;
  System.Collections.Generic.Dictionary<TEnum,int> mapMember2Index;
  #endregion


  #region "ctors"
  public Set()
  {
    Initialize();
    members = new System.Collections.BitArray(mapMember2Index.Count);
  }

  private Set(System.Collections.BitArray members)
  {
    Initialize();
    this.members = members;
  }

  private void Initialize()
  {
    if (typeof(TEnum).BaseType != typeof(System.Enum))
      throw new ApplicationException(string.Format(
        "Generic type parameter <{0}> is not an enum type!",
        typeof(TEnum).FullName));
    flagsEnum = typeof(TEnum).GetCustomAttributes(typeof(
      System.FlagsAttribute),true).Length > 0;
    int i = 0;
    mapMember2Index = new Dictionary<TEnum,int>();
    foreach (TEnum m in Enum.GetValues(typeof(TEnum)))
      mapMember2Index.Add(m,i++);
  }
  #endregion
  

  #region "Working with the set"

  public void Clear()
  {
    members.SetAll(false);
  }

  public Set<TEnum> Add(TEnum member)
  {
    members.Set(mapMember2Index[member],true);
    return this;
  }

  public Set<TEnum> Add(Set<TEnum> otherSet)
  {
    if (otherSet != null) members.Or(otherSet.members);
    return this;
  }

  public Set<TEnum> Remove(TEnum member)
  {
    members.Set(mapMember2Index[member],false);
    return this;
  }

  public Set<TEnum> Remove(Set<TEnum> otherSet)
  {
    if (otherSet != null)
      for (int i = 0; i < members.Count; i++)
        if (otherSet.members[i])
          members[i] = false;
    return this;
  }

  public Set<TEnum> Intersect(Set<TEnum> otherSet)
  {
    if (otherSet != null) members.And(otherSet.members);
    return this;
  }

  public bool Contains(TEnum member)
  {
    return members[mapMember2Index[member]];
  }

  public int Cardinality
  {
    get
    {
      return members.Length;
    }
  }
  #endregion


  #region "Overrides"

  public override bool Equals(object obj)
  {
    return this == (Set<TEnum>)obj;
  }

  public override int GetHashCode()
  {
    return members.GetHashCode();
  }

  public override string ToString()
  {
    string[] names = Enum.GetNames(typeof(TEnum));
    StringBuilder memberNames = new StringBuilder("[");
    for (int i = 0; i < members.Count; i++)
      if (members[i])
      {
        if (memberNames.Length > 1) memberNames.Append(",");
        memberNames.Append(names[i]);
      }
    memberNames.Append("]");
    return memberNames.ToString();
  }
  #endregion


  #region "Operators"

  /// <summary>Intersection</summary>
  public static Set<TEnum> operator &(Set<TEnum> left,Set<TEnum> right)
  {
    System.Collections.BitArray result = new System.Collections.BitArray(new bool[left.members.Count]);
    result.Or(left.members);
    if (right != null) result.And(right.members);
    return new Set<TEnum>(result);
  }

  /// <summary>Union</summary>
  public static Set<TEnum> operator |(Set<TEnum> left,Set<TEnum> right)
  {
    System.Collections.BitArray result = new System.Collections.BitArray(
      new bool[left.members.Count]);
    result.Or(left.members);
    if (right != null) result.Or(right.members);
    return new Set<TEnum>(result);
  }

  public static bool operator ==(Set<TEnum> left,Set<TEnum> right)
  {
    if (right != null)
    {
      for (int i = 0; i < left.members.Count; i++)
        if (left.members[i] != right.members[i]) return false;
      return true;
    }
    else return false;
  }

  public static bool operator !=(Set<TEnum> left,Set<TEnum> right)
  {
    return !(left == right);
  }
  #endregion


  #region "Iterator"
  public IEnumerator<TEnum> GetEnumerator()
  {
    TEnum[] memberValues = (TEnum[])Enum.GetValues(typeof(TEnum));
    for (int i = 0; i < members.Count; i++)
      if (members[i]) yield return memberValues[i];
  }
  #endregion
}