C#:在整数集上键入安全性(例如枚举)

时间:2013-03-06 17:29:34

标签: c# enums type-safety

我有一个案例,我有几组数字(寄存器值)。我想提高可读性并检查适当的类型(在某些函数中只有某些值有意义)。

在我的特定实现中,我将它们设为枚举 - 所以我现在有一组枚举。

现在我似乎已经达到了这种方法的最终目的,因为我想将它们分成某些应用程序的有效枚举集 - 所以函数A可以例如从(enumA,enumB和enumC中取值)作为输入,但不是enumD,它是对不同功能的描述。

我已经查看了接口和枚举继承中的枚举 - 两者都是死路一条,在C#中是不可能的。

我现在想知道这个问题的解决方案可能会是什么样子。我想得到关于可能值的智能感知,并且还有一些类型安全性,所以我不能(好吧,至少不是没有恶意地投射它)提供错误的值。

如何实现这一目标?

(可能的解决方案是简单地编写几个函数,使用几个不同的枚举 - 仍然可能但不是很好,或类似Is there a name for this pattern? (C# compile-time type-safety with "params" args of different types) - 两者似乎都不太好。)

4 个答案:

答案 0 :(得分:4)

一种选择是废弃枚举并使用您自己的用于模仿枚举的clases。设置它们会有更多的工作,但一旦你这样做就很容易使用,并且能够拥有你所描述的功能。

public class Register
{
    private int value;

    internal Register(int value)
    {
        this.value = value;
    }

    public static readonly Register NonSpecialRegister = new Register(0);
    public static readonly Register OtherNonSpecialRegister = new Register(1);

    public static readonly SpecialRegister SpecialRegister 
        = SpecialRegister.SpecialRegister;
    public static readonly SpecialRegister OtherSpecialRegister 
        = SpecialRegister.OtherSpecialRegister;

    public override int GetHashCode()
    {
        return value.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        Register other = obj as Register;
        if (obj == null)
            return false;

        return other.value == value;
    }
}

public class SpecialRegister : Register
{
    internal SpecialRegister(int value) : base(value) { }

    public static readonly SpecialRegister SpecialRegister = new SpecialRegister(2);
    public static readonly SpecialRegister OtherSpecialRegister = new SpecialRegister(3);
}

鉴于此,您可以使用以下方法:

public static void Foo(Register reg)
{
}

可以接受任何注册,可以像:

一样调用
Foo(Register.NonSpecialRegister);
Foo(Register.OtherSpecialRegister);

然后你可以有另一种方法,例如:

public static void Bar(SpecialRegister reg)
{
}

哪些人无法接受Register.NonSpecialRegister,但可以接受Register.OtherSpecialRegisterSpecialRegister.SpecialRegister

答案 1 :(得分:1)

听起来你已经用尽了CLR上静态类型系统的功能。您仍然可以通过使用一个类来包装每个整数来验证您尝试存储在其中的值实际上是静态集的成员,从而获得运行时验证。

如果您有可靠的测试套件或者愿意进行手动测试,那么至少会捕获错误而不是导致静默数据损坏的错误。

如果您想要分开多个“集合”,则可以使用类继承,也可以使用一组用户定义的转换运算符来验证转换在运行时是否正常。

我不知道您有什么具体要求,但也许您可以使用基于类的继承来静态检查某些属性。在这种情况下,基类将是更大的集合,派生类将专门化允许值集合。

答案 2 :(得分:1)

您基本上有两种选择:

选项1:多个枚举

创建多个枚举,每个应用程序一个枚举,并复制每个枚举中的值。然后你可以在它们之间施放。例如:

enum App1
{
    Data1 = AppAll.Data1,
    Data2 = AppAll.Data2,
    Data42 = AppAll.Data42,
}

enum App2
{
    Data2 = AppAll.Data2,
    Data16 = AppAll.Data16,
    Data42 = AppAll.Data42,
}

enum AppAll
{
    Data1 = 1,
    Data2 = 2,
    Data16 = 16,
    Data42 = 42,
}

App1 value1 = (App1)AppAll.Data2;
App2 value2 = (App2)value1;

这将为您提供智能感知。

选项2:确定允许的

创建一个返回允许值的布尔值的方法(对于每个应用程序,这可能是虚拟的和覆盖的)。然后,当枚举值错误时,您可以抛出异常。

public bool IsAllowed(AppAll value)
{
    return value == AppAll.Data2
        || value == AppAll.Data16
        || value == AppAll.Data42;
}


if (!IsAllowed(value))
    throw new ArgumentException("Enum value not allowed.");

这不会给你智能感知。


一些注意事项:

  • 您不能继承枚举,因为在封面下枚举表示为structs(即值类型)。
  • 在C#中,您可以将任何值转换为枚举类型,即使它不是它的成员。例如,即使没有值(App1)1337的成员,我也可以1337

答案 3 :(得分:1)

如果您想要编译类型检查,那么对于不同的情况,您最好使用不同的枚举。如果你想拥有一个包含所有可能性的主枚举,你可以编写一个测试,确保所有“子”枚举列表都是主要的有效子集(就Int强制转换而言)。

作为替代方案,我不得不怀疑(因为没有提供代码,我只能想知道)如果你可能没有更好地使用带有每个枚举选项的方法的对象。然后使用各种方法而不是枚举继承对象。 (毕竟,似乎您使用Enums作为方法签名的代理)。