将枚举T的值映射到有效的标志值(0,1,2,4,8,16,24 ......)

时间:2016-04-15 20:52:20

标签: c# keyboard mapping bit-manipulation enumeration

假设我有以下枚举:

public enum SomeEnum
{
    A, // = 0
    B, // = 1
    C, // = 2
    D, // = 3
    E, // = 4
    ...
}

基本上,我想要做的是将每个值映射到有效的掩码值(0,1,2,4,8,16,32,64,128 ......),以便SomeEnum.A等效到0,SomeEnum.B为1,SomeEnum.C为2, SomeEnum.D为4,SomeEnum.E为8等等。我有点工作,但我面临另一个问题:给定枚举的值越多,映射越大,可能会产生一个超级超巨长长多长。 有没有任何已知的技术?

这是我的代码:

public class Flagger<T> where T : struct
    {
        private static Dictionary<int, ulong> dictionary = new Dictionary<int, ulong>();

        static Flagger()
        {
            int indexer = 0;

            // Since values can be duplicated, we use names instead
            foreach (String name in Enum.GetNames(typeof(T)))
            {
                ulong value = 1UL << indexer++; // 0, 1, 2, 4, 8, 16...

                Console.WriteLine("{0} generated value {1}", name, value);

                dictionary.Add(name.GetHashCode(), value); 
            }
        }

        private ulong flags;

        public void Add(T value)
        {
            // Create hash only once for both checkup and storation
            int hash = value.ToString().GetHashCode();

            if (Check(hash))
            {
                ulong flag = dictionary[hash];

                flags &= flag;
            }
        }

        public void Remove(T value)
        {
            // Create hash only once for both checkup and storation
            int hash = value.ToString().GetHashCode();

            if (Check(hash))
            {
                ulong flag = dictionary[hash];

                flags &= ~flag;
            }            
        }

        /// <summary>
        /// Tests whether a value has already been added or not
        /// </summary>
        public bool Check(T value)
        {
            int hash = value.ToString().GetHashCode();

            return Check(hash);
        }

        /// <summary>
        /// Quick checkup because no hash needs to be computed
        /// </summary>
        private bool Check(int hash)
        {
            if (dictionary.ContainsKey(hash))
            {
                ulong flag = dictionary[hash];

                return (flags & flag) == flag;
            }

            return false;
        }
    }

所有这一切的原因是我正在使用System.Window.Input.Key枚举,我无法测试是否启用了某些标志,例如:

using System.Windows.Input;

int vk = 0x55; // U
Key key = KeyInterop.KeyFromVirtualKey(vk);

if ((Key.W & key) == key)
{
    Console.WriteLine("True!");
}

上面的“if”条件使我返回true,这不是真的!

1 个答案:

答案 0 :(得分:1)

使用位移:

[Flags]
public enum MyEnum
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3
}

编辑:在澄清问题之后,这就是你如何评估标记的键枚举值是否包含不同类型但名称相似的枚举值的等效值。

[Flags]
public enum Keys1
{
    O = 0,
    K = 1,
    A = 1 << 1,
    Y = 1 << 2
}

public enum Keys2
{
    O,
    K,
    A,
    Y
}

public bool DoesIncludeKey(Keys1 keys1, Keys2 keys2)
{
    var keys1Names = keys1.ToString().Split(',');
    return keys1Names.Contains(keys2.ToString());
}

//ToString() on keysVals results in "O,K", 
//which is what makes the above function work.
var keysVals = Keys1.O | Keys1.K;

//true!
var includesK = DoesIncludeKey(keysVals, Keys2.K);
//false.
var includesA = DoesIncludeKey(keysVals, Keys2.A);