簡體   English   中英

C#enum type-safety

[英]C# enum type-safety

有沒有辦法強制C#枚舉只接受幾個明確命名的常量之一,還是有另一個功能呢? C#參考有了這個想法:

可以將任意整數值分配給枚舉類型。 但是,您不應該這樣做,因為隱含的期望是枚舉變量只保存枚舉定義的值之一。 將任意值分配給枚舉類型的變量是為了引入高風險的錯誤。

(一種新的語言設計允許這種邋。。這讓我感到困惑。)

據我所知,你不能阻止C#允許枚舉和整數之間的轉換。

作為一種變通方法,您可以使用具有受限實例化的自定義類型。 用法看起來類似,但您也可以為此類型定義方法和運算符。

說你有這個枚舉:

enum DayOfWeek
{
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday 
}

您可以在其位置使用密封類。 優點是您可以免費進行比較(因為在這種情況下,值比較和參考比較是等效的)。 缺點是(像C#中的所有引用類型一樣),它可以為空。

sealed class DayOfWeek
{
    public static readonly DayOfWeek Monday = new DayOfWeek(0);
    public static readonly DayOfWeek Tuesday = new DayOfWeek(1);
    public static readonly DayOfWeek Wednesday = new DayOfWeek(2);
    public static readonly DayOfWeek Thursday = new DayOfWeek(3);
    public static readonly DayOfWeek Friday = new DayOfWeek(4);
    public static readonly DayOfWeek Saturday = new DayOfWeek(5);
    public static readonly DayOfWeek Sunday = new DayOfWeek(6);

    private readonly int _value;

    private DayOfWeek(int value) 
    {
        _value = value;
    }
}

或者您可以使用結構。 它的優點是它不可空,因此它更類似於枚舉。 缺點是你必須手動實現比較代碼:

struct DayOfWeek
{
    public static readonly DayOfWeek Monday = new DayOfWeek(0);
    public static readonly DayOfWeek Tuesday = new DayOfWeek(1);
    public static readonly DayOfWeek Wednesday = new DayOfWeek(2);
    public static readonly DayOfWeek Thursday = new DayOfWeek(3);
    public static readonly DayOfWeek Friday = new DayOfWeek(4);
    public static readonly DayOfWeek Saturday = new DayOfWeek(5);
    public static readonly DayOfWeek Sunday = new DayOfWeek(6);

    private readonly int _value;

    private DayOfWeek(int value)
    {
        _value = value;
    }

    public bool Equals(DayOfWeek other)
    {
        return _value == other._value;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        return obj is DayOfWeek && Equals((DayOfWeek)obj);
    }

    public override int GetHashCode()
    {
        return _value;
    }

    public static bool operator ==(DayOfWeek op1, DayOfWeek op2)
    {
        return op1.Equals(op2);
    }

    public static bool operator !=(DayOfWeek op1, DayOfWeek op2)
    {
        return !(op1 == op2);
    }
}

將任何整數強制轉換為枚舉的能力主要是出於性能原因,但實現為值類型的枚舉無法保護不包含未定義的值。 考慮一個枚舉如:

public enum Condition {
  Right = 1,
  Wrong = 2
}

即使枚舉變量的賦值僅限於定義的值,您仍然可以通過簡單地將其放在類中來創建未定義的值:

public class Demo {
  public Condition Cond;
}

創建類的實例時,成員初始化為零,因此Cond成員變量將具有未定義的值(Condition)0

您可以創建一個包裝類,以確保枚舉值在定義的值中:

public sealed class SafeEnum<T> where T : struct {

  public T Value { get; private set; }

  public SafeEnum(T value) {
    if (!(value is Enum)) {
      throw new ArgumentException("The type is not an enumeration.");
    }
    if (!Enum.IsDefined(typeof(T), value)) {
      throw new ArgumentException("The value is not defined in the enumeration.");
    }
    Value = value;
  }

}

例:

var cond = new SafeEnum<Condition>(Condition.Right); // works
Condition d = cond.Value;

var cond = new SafeEnum<int>(42); // not an enum

var cond = new SafeEnum<Condition>((Condition)42); // not defined

該類的實例只能包含枚舉中定義的值,否則構造函數將不允許創建實例。

由於類是不可變的,因此值不能更改為未定義的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM