簡體   English   中英

檢查不能彼此共存的按位標志

[英]Check bitwise flags that cannot co-exist with each other

我有旗幟

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”語句,如何實現?

要將位設置在位置n ,您需要設置值2 ^ n

因此,如果您要檢查是否僅指定了一個標志,那么您只想詢問數字是否為2的冪。

這是一個有關如何執行此操作的問題: 如何檢查數字是否為2的冪

就像GrahamS所說的那樣,您可能會讀到這樣的問題,即必須設置一位(即不能為零)。 因此,此外,請檢查它是否為非零值並且小於或等於C。

也許不是最優雅的解決方案,但我認為它應該起作用:

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

    return 
        flags == 0 ||
        flags == A ||
        flags == B ||
        flags == C;
}

為什么不對標志使用Enum,並檢查int值是否在枚舉中定義。

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

void Check(int flags)
{
    bool isValid = Enum.IsDefined(typeof(Flags), flags);
    ...
}

這是帶有switch的實現:

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

僅當ABC是文字(即用const標記)時,它才有效(在C#中)。 否則,您可以執行以下操作:

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

我認為可能有比三個最低位更大的有效位,因此將其忽略。 我還假設ABC都不有效(在我的解釋中這不是共存的)。

我要發表評論,但格雷厄姆斯所說的話很重要,足以說明這一點。

當您特別希望能夠設置倍數時,通常使用標志。 這是我們的任務枚舉的示例

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

我不會建議這樣的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM