2015-09-05 194 views
2

有没有办法强制C#枚举只接受几个明确命名的常量之一,或者是否有另一个功能呢? C#参考有这个后缀:C#枚举类型安全

可以将任意的整数值赋给一个枚举类型。 但是,您不应该这样做,因为隐式期望是 enum变量将仅保存由 枚举定义的值之一。将任意值分配给枚举类型的变量 类型将导致错误的高风险。

(一种新的语言的设计,让这种草率的,这是莫名其妙的给我。)

回答

2

投一个枚举的任意整数的能力是主要是因为性能的原因,但实现的枚举作为一个值类型根本无法保护包含未定义的值。考虑一个枚举,如:

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 

的类的实例只能包含一个值,在枚举中定义,否则构造函数将不允许创建实例。

由于该类是不可变的,因此该值不能更改为未定义的值。

3

据我所知,你不能阻止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); 
    } 
} 
+1

有一件事情会让事情变得更糟 - 现在你可以将'null'分配给'DayOfWeek',因为它是一个类。 – MarcinJuraszek

+0

@MarcinJuraszek你是对的。我已经包含了一种替代方法。 –

+1

'struct'方法给出了另一个问题 - 您可以通过调用无过于构造函数来创建附加值。无论如何,编译器都会为每个结构体默认定义它。 – MarcinJuraszek