我有旗帜
int A = 1;
int B = 2;
int C = 4;
我想检查一下,只能为一个函数指定一个标志
check(A | B | C) ; // invalid
check(A); // valid
check(B); // valid
check(B | C); // invalid
void check(int flags) {
// check that if A is specified, then B and C can't
// check that if B is specified, then A and C can't
// check that if C is specified, then B and A can't
}
如果没有大量的“if”陈述,我怎样才能做到这一点?
答案 0 :(得分:6)
要将位设置为 n ,您需要设置值 2 ^ n 。
因此,如果您想检查是否只指定了其中一个标志,那么您只想询问该数字是否为2的幂。
以下是关于如何执行此操作的问题:How to check if a number is a power of 2
正如格雷厄姆所说,你可以读到这个问题,说必须设置一个比特(即它不能为零)。所以要做到这一点,另外,检查它是否为非零并且它小于或等于C.
答案 1 :(得分:2)
也许不是最优雅的解决方案,但我认为它应该有效:
bool check(int flags) {
int A = 1;
int B = 2;
int C = 4;
return
flags == 0 ||
flags == A ||
flags == B ||
flags == C;
}
答案 2 :(得分:0)
为什么不使用Enum作为标志,并检查枚举中是否定义了int值。
enum Flags
{
A = 1,
B = 2,
C = 4
}
void Check(int flags)
{
bool isValid = Enum.IsDefined(typeof(Flags), flags);
...
}
答案 3 :(得分:0)
这是一个带开关的实现:
void check(int flags) {
swicth (flags & (A | B | C)) {
case A:
case B:
case C:
case 0:
return true;
default:
return false;
}
}
仅当A
,B
和C
为文字时,才会有效(在C#中),即标有const
。否则你也可以这样做:
void check(int flags) {
int relevantPart = flags & (A | B | C);
return relevantPart == A || relevantPart == B || relevantPart == C || relevantPart == 0;
}
否则使用二次幂技巧(来自Joe的回答):
void check(int flags) {
int relevantPart = flags & (A | B | C);
return (relevantPart & (relevantPart - 1)) == 0;
}
我假设可能存在比三个最小位更多的有效位,并且它们将被忽略。我还假设A
,B
和C
都没有效(这在我的解释中并不存在)。
答案 4 :(得分:0)
我打算发表评论,但格雷厄姆所说的话非常重要,值得详细阐述。
当您特别希望能够设置倍数时,通常会使用标志。以下是我们的任务枚举
的示例namespace Shared.Enumerations
{
[Flags]
public enum TaskStatusEnum
{
NotSet = 0,
Open = 1,
Canceled = 2,
Complete = 4,
OnHold = 8,
Inactive = 32,
All = Open | Canceled | Complete | OnHold | Inactive
}
}
我们这样做,所以我们可以说给我们任何开放或暂停的任务。
TaskList activeTasks = taskListManager.TaskList.FindAll(target.Name, target.TaskType, (TaskStatusEnum.Open | TaskStatusEnum.OnHold));
当然,使用普通枚举,您一次只能设置一件事。您实际上可以执行以下操作。
[TestMethod]
public void checkEnumVals()
{
var ts = TaskStatusTestEnum.Open;
ts |= TaskStatusTestEnum.OnHold;
bool matchBoth = false;
if ((ts & TaskStatusTestEnum.OnHold) == TaskStatusTestEnum.OnHold && (ts & TaskStatusTestEnum.Open) == TaskStatusTestEnum.Open)
matchBoth = true;
Assert.IsTrue(matchBoth);
}
我不会建议这样的事情。