枚举超出范围
本文关键字:范围 枚举 | 更新日期: 2023-09-27 18:29:49
在我的测试函数中处理无效枚举的最佳方法是什么。该功能的设计允许我比较两个项目是否相互兼容。理想情况下,如果索引超出范围,我希望返回false作为结果。
public enum VNodeClassID
{
Default,
Apple,
Orange,
Grape,
BlueBerry,
Watermellon,
// more items to be added
}
// square 2d array
bool[,] validation = new bool[,]
{
{ false, true, true, false, true, true },
{ false, false, true, true, false, true },
{ false, true, true, false, true, true },
{ false, true, false, true, true, false },
{ false, true, true, true, false, true },
{ false, false, true, false, true, true }
};
public void Test()
{
var itemA = VNodeClassID.Default;
var itemB = VNodeClassID.Watermellon;
bool results = validation[(int)itemA, (int)itemB];
Console.WriteLine("{0}: {1}-{2}", results, itemA, itemB);
}
您可以编写一个方法来返回项目是否兼容,如下所示:
public bool IsCompatible(VNodeClassID itemA, VNodeClassID itemB)
{
if (!Enum.IsDefined(typeof(VNodeClassID), itemA))
return false;
if (!Enum.IsDefined(typeof(VNodeClassID), itemB))
return false;
return validation[(int)itemA, (int)itemB];
}
那么你的测试方法会是这样的:
public void Test()
{
var itemA = VNodeClassID.Default;
var itemB = VNodeClassID.Watermellon;
bool results = IsCompatible(itemA, itemB);
Console.WriteLine("{0}: {1}-{2}", results, itemA, itemB);
}
您可以这样做:
var valid_values =
Enum.GetValues(typeof (VNodeClassID)) //Get all valid values of VNodeClassID
.Cast<VNodeClassID>()
.ToList();
bool results =
valid_values.Contains(itemA) && //itemA is within range
valid_values.Contains(itemB) && //itemB is within range
validation[(int)itemA, (int)itemB];
我建议使用[FlagsAttrbute]
并存储一个包含与true
对应的位的字典。类似下面的代码:
[Flags]
public enum VNodeClassID
{
Default = 0,
Apple = 1 << 0, // Apple = 1
Orange = 1 << 1, // Orange = 2
Grape = 1 << 2, // Grape = 4
BlueBerry = 1 << 3, // Bluebery = 8
Watermellon = 1 << 4, // Watermelon = 16
// more items to be added
}
class Program
{
static Dictionary<VNodeClassID, int> validation = new Dictionary<VNodeClassID, int>();
static void Main(string[] args)
{
//{ D A=1 O=2 G=4 B=8 W=16
// { false, true, true, false, true, true },
// { false, false, true, true, false, true },
// { false, true, true, false, true, true },
// { false, true, false, true, true, false },
// { false, true, true, true, false, true },
// { false, false, true, false, true, true }
//};
// set like this
MakeCompatibe(VNodeClassID.Watermellon,VNodeClassID.Orange|VNodeClassID.BlueBerry|VNodeClassID.Watermellon);
// or
validation[VNodeClassID.Default] = 1 + 2 + 8 + 16;
validation[VNodeClassID.Apple] = 2 + 4 + 16;
validation[VNodeClassID.Orange] = 1 + 2 + 8 + 16;
validation[VNodeClassID.Grape] = 1 + 4 + 8;
validation[VNodeClassID.BlueBerry] = 1 + 2 + 4 + 16;
validation[VNodeClassID.Watermellon] = 2 + 8 + 16;
Debug.Assert(CheckCompatibe(VNodeClassID.Apple, VNodeClassID.Watermellon));
Debug.Assert(!CheckCompatibe(VNodeClassID.Default, VNodeClassID.Grape));
}
static void MakeCompatibe(VNodeClassID item, params VNodeClassID[] items)
{
int sum = items.Sum((v) => (int)v);
validation[item] = sum;
}
static bool CheckCompatibe(VNodeClassID item, VNodeClassID other)
{
if (validation.ContainsKey(item))
{
int sum = validation[item];
return (sum & (int)other) > 0;
}
return false;
}
}
它是如何工作的?请记住二进制系统。enum
中的每个项目表示不同值的bit
。当它们组合在一起时,就会产生一个数字,比如27。为了检查是否在27中设置了例如8的位,请执行AND
操作并查看结果是否为非零。
27 : 00011011
8 : 00001000 AND
-------------
: 00001000 CHECK
类似的东西
Dictionary<<Tuple<VNodeClassID,VNodeClassID>,bool>>
可能是实现类型安全性和语义正确性的更好方法。示例:
public class ValidKey: Tuple<VNodeClassID, VNodeClassID>
{
public ValidKey(VNodeClassID a, VNodeClassID b) : base(a, b) { }
}
static Dictionary<ValidKey, bool> validation = new Dictionary<ValidKey, bool>() {
{ new ValidKey(VNodeClassID.Apple, VNodeClassID.Watermellon), true },
{ new ValidKey(VNodeClassID.Apple, VNodeClassID.Orange), true },
{ new ValidKey(VNodeClassID.Orange, VNodeClassID.Grape), true }
};
bool Validate(VNodeClassID thing1, VNodeClassID thing2)
{
var key = new ValidKey(thing1, thing2);
return validation.ContainsKey(key) ? validation[key] : false;
}
用法:
bool a = Validate(VNodeClassID.Apple, VNodeClassID.Watermellon);
bool b = Validate(VNodeClassID.Grape, VNodeClassID.BlueBerry);