繁体   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