c#:整型集合(如枚举)的类型安全
本文关键字:枚举 类型安全 整型 集合 | 更新日期: 2023-09-27 18:02:30
我有一个情况,我有几组数字(寄存器值)。我想提高可读性,并检查适当的类型(只有某些值在某些函数中有意义)。
在我的特殊实现中,我把它们变成了枚举——所以我现在有了一组枚举。
现在我似乎已经达到了这种方法的终点,因为我想将它们划分为特定应用程序的有效枚举集-因此函数A可以例如将(来自)enumA, enumB和enumC的值作为输入,但不是enumD,这是不同功能的描述。
我已经研究了接口中的枚举和枚举继承——两者都是死胡同,在c#中是不可能的。
我现在想知道这个问题的解决方案是什么样子的。我想获得对可能值的智能感知,同时也有一些类型安全,这样我就不能(好吧,至少在没有恶意强制转换的情况下)在。
中提供错误的值。如何实现这一点?
(可能的解决方案是简单地编写几个函数,使用几个不同的枚举-仍然可能,但不是很好,或者类似于此模式有一个名称吗?c#编译时类型安全"params"不同类型的Args) -两者看起来都不太好
一种选择是放弃枚举并使用您自己设计的类来模拟枚举。对你来说,设置它们会有更多的工作,但是一旦你这样做了,它就会很容易使用,并且能够拥有你所描述的功能。
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.OtherSpecialRegister
或SpecialRegister.SpecialRegister
。
听起来好像您已经用尽了CLR上静态类型系统的功能。您仍然可以通过用一个类包装每个整数来获得运行时验证,该类验证您试图存储在其中的值实际上是静态集合的成员。
如果你有一个可靠的测试套件,或者愿意进行手动测试,这至少会捕获错误,而不是导致沉默数据损坏的错误。
如果你有多个想要分开的"集合",你可以使用类继承,或者使用一组用户定义的转换操作符,这些操作符在运行时验证转换是否正确。
我不知道你有什么具体的要求,但也许你可以使用基于类的继承来静态地检查一些属性。在这种情况下,基类将是较大的集合,派生类将专门化允许的值的集合。
你基本上有两个选择:
选项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
的成员。如果您想要编译类型检查,您最好使用不同的枚举来区分不同的情况。如果你想拥有一个包含所有可能性的主枚举,你可以编写一个测试来确保你所有的"子"枚举列表都是主枚举的有效子集(就Int类型强制转换而言)。
作为另一种选择,我不得不怀疑(因为没有提供代码,我只能怀疑),如果为每个enum选项提供方法的对象可能不会更好地为您服务。然后用各种方法而不是枚举继承我们的对象。(毕竟,您似乎正在使用枚举作为方法签名的代理)。