2

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

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

现在我似乎已经结束了这种方法,因为我想将它们划分为某些应用程序的有效枚举集 - 因此函数 A 可以例如将(来自)enumA、enumB 和 enumC 的值作为输入,但不是 enumD这是对不同功能的描述。

我已经研究过接口中的枚举和枚举继承——两者都是死胡同,在 C# 中是不可能的。

我现在想知道这个问题的解决方案会是什么样子。我想对可能的值进行智能感知,并且还具有一些类型安全性,这样我就不能(好吧,至少在没有恶意强制转换的情况下)输入错误的值。

如何做到这一点?

(可能的解决方案是简单地编写几个采用几个不同枚举的函数 - 仍然可能但不是很好,或者类似这种模式有名称吗?(C# compile-time type-safety with "params" args of different types) - 两者似乎都不太好。)

4

4 回答 4

4

一种选择是废弃枚举并使用您自己的类来模拟枚举。设置它们需要做更多的工作,但是一旦你完成了,它就会很容易使用,并且能够拥有你所描述的功能。

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)
{
}

哪个不能接受 a Register.NonSpecialRegister,但可以接受 a Register.OtherSpecialRegisteror SpecialRegister.SpecialRegister

于 2013-03-06T17:50:26.260 回答
1

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

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

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

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

于 2013-03-06T17:35:34.147 回答
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;

这将为您提供 IntelliSense。

选项 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.");

这不会给您 IntelliSense。


几点注意事项:

  • 您不能继承枚举,因为在幕后枚举表示为structs(即值类型)。
  • 在 C# 中,您可以从字面上将任何值强制转换为您的枚举类型,即使它不是枚举类型的成员。例如,(App1)1337即使没有具有 value 的成员,我也可以这样做1337
于 2013-03-06T17:35:48.023 回答
1

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

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

于 2013-03-06T17:37:41.547 回答