使用C#中的位掩码 [英] Using a bitmask in C#

查看:206
本文介绍了使用C#中的位掩码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说我有以下

int susan = 2; //0010
int bob = 4; //0100
int karen = 8; //1000

和我通过10(8 + 2)作为参数的方法,我想脱code这意味着苏珊和Karen

and I pass 10 (8 + 2) as a parameter to a method and I want to decode this to mean susan and karen

我知道10是1010

I know that 10 is 1010

但我怎么可以做一些逻辑,看是否有特定的位在

but how can I do some logic to see if a specific bit is checked as in

if (condition_for_karen) // How to quickly check whether effective karen bit is 1

现在,所有我能想到的是检查我通过数量是否

Right now all i can think of is to check whether the number i passed is

14 // 1110
12 // 1100
10 // 1010
8 //  1000

当我在现实世界中的场景实际比特数量较多,这似乎是不切实际的,为什么要使用口罩,只检查我是否不符合条件卡伦只是一个更好的办法?

When I have a larger number of actual bits in my real world scenario, this seems impractical, what is a better way using a mask to just check whether or not I meet the condition for just karen?

我能想到的左移再回到当时右移,然后返回一个比我感兴趣的其他明确位,但是这也似乎过于复杂。

I can think of shifting left then back then shifting right then back to clear bits other than the one I'm interested in, but this also seems overly complex.

推荐答案

传统的方式做,这是使用标记的一个属性枚举

The traditional way to do this is to use the Flags attribute on an enum:

[Flags]
public enum Names
{
    None = 0,
    Susan = 1,
    Bob = 2,
    Karen = 4
}

然后你会检查特定名称如下:

Then you'd check for a particular name as follows:

Names names = Names.Susan | Names.Bob;

// evaluates to true
bool susanIsIncluded = (names & Names.Susan) != Names.None;

// evaluates to false
bool karenIsIncluded = (names & Names.Karen) != Names.None;

逻辑按位的组合可能会很难记住,所以我让生活在我自己更容易被 FlagsHelper 类*:

// The casts to object in the below code are an unfortunate necessity due to
// C#'s restriction against a where T : Enum constraint. (There are ways around
// this, but they're outside the scope of this simple illustration.)
public static class FlagsHelper
{
    public static bool IsSet<T>(T flags, T flag) where T : struct
    {
        int flagsValue = (int)(object)flags;
        int flagValue = (int)(object)flag;

        return (flagsValue & flagValue) != 0;
    }

    public static void Set<T>(ref T flags, T flag) where T : struct
    {
        int flagsValue = (int)(object)flags;
        int flagValue = (int)(object)flag;

        flags = (T)(object)(flagsValue | flagValue);
    }

    public static void Unset<T>(ref T flags, T flag) where T : struct
    {
        int flagsValue = (int)(object)flags;
        int flagValue = (int)(object)flag;

        flags = (T)(object)(flagsValue & (~flagValue));
    }
}

这将让我把上面的code为:

This would allow me to rewrite the above code as:

Names names = Names.Susan | Names.Bob;

bool susanIsIncluded = FlagsHelper.IsSet(names, Names.Susan);

bool karenIsIncluded = FlagsHelper.IsSet(names, Names.Karen);

请注意我还可以做这个添加卡伦来设置的:

Note I could also add Karen to the set by doing this:

FlagsHelper.Set(ref names, Names.Karen);

和我可以以类似的方式删除苏珊

And I could remove Susan in a similar way:

FlagsHelper.Unset(ref names, Names.Susan);

<子> *由于Porges指出的那样,使用isset 法的等效上文已经存在于.NET 4.0:<一href=\"http://msdn.microsoft.com/en-us/library/system.enum.hasflag.aspx\"><$c$c>Enum.HasFlag.在设置请解除的方法不会出现有等价物,虽然,所以我还是会说这个类有一些可取之处。

*As Porges pointed out, an equivalent of the IsSet method above already exists in .NET 4.0: Enum.HasFlag. The Set and Unset methods don't appear to have equivalents, though; so I'd still say this class has some merit.

请注意:使用枚举只是的常规的解决这个问题的途径。你完全可以把所有上述code的使用,而不是整数,它会很好的工作。

Note: Using enums is just the conventional way of tackling this problem. You can totally translate all of the above code to use ints instead and it'll work just as well.

这篇关于使用C#中的位掩码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆