1

我有旗帜

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”语句,我怎么能做到这一点?

4

5 回答 5

6

要在位置n设置位,您需要设置值2^n

因此,如果您想检查是否只指定了一个标志,那么您只需询问该数字是否是 2 的幂。

这里有一个关于如何做到这一点的问题:如何检查一个数字是否是 2 的幂

正如 GrahamS 所说,您可以将问题解读为必须设置一个位(即不能为零)。因此,为此,此外,请检查它是否非零且小于或等于 C。

于 2013-07-30T12:38:13.143 回答
2

也许不是最优雅的解决方案,但我认为它应该有效:

bool check(int flags) {
    int A = 1;
    int B = 2;
    int C = 4;

    return 
        flags == 0 ||
        flags == A ||
        flags == B ||
        flags == C;
}
于 2013-07-30T12:38:14.817 回答
0

为什么不使用枚举作为标志,并检查枚举中是否定义了 int 值。

enum Flags
{
    A = 1,
    B = 2,
    C = 4
}

void Check(int flags)
{
    bool isValid = Enum.IsDefined(typeof(Flags), flags);
    ...
}
于 2013-07-30T12:57:58.517 回答
0

这是一个带有开关的实现:

void check(int flags) {
  swicth (flags & (A | B | C)) {
    case A:
    case B:
    case C:
    case 0:
      return true;
    default:
      return false;
  }
}

仅当A,BC是文字,即标有const. 否则,您可以使用以下方法执行相同操作:

void check(int flags) {
  int relevantPart = flags & (A | B | C);
  return relevantPart == A || relevantPart == B || relevantPart == C || relevantPart == 0;
}

否则使用二次幂技巧(来自乔的回答):

void check(int flags) {
  int relevantPart = flags & (A | B | C);
  return (relevantPart & (relevantPart - 1)) == 0;
}

我假设可能有比三个最低位更多的有效位,并且它们将被忽略。我还假设A, B, 也不C是有效的(这在我的解释中并不共存)。

于 2013-07-30T13:15:25.017 回答
0

我打算发表评论,但 GrahamS 所说的非常重要,足以保证对这一点进行一些详细说明。

当您特别希望能够设置倍数时,通常使用标志。这是我们的任务枚举的示例

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

我不会建议这样的事情。

于 2013-07-30T13:16:26.717 回答