2012-11-19 98 views
5

我已经创建了一个扩展方法等..检查是否完全只是这些标志在枚举集

public static bool AllFlagsSet<T>(this T input, params T[] values) where T : struct, IConvertible 
{ 
    bool allSet = true; 
    int enumVal = input.ToInt32(null); 

    foreach (T itm in values) 
    { 
     int val = itm.ToInt32(null); 
     if (!((enumVal & val) == val)) 
     { 
      allSet = false; 
      break; 
     } 
    } 

    return allSet; 
} 

这为我所需要的目的的伟大工程,但是我现在有一个要求,以创建具有的方法相同的签名检查是否只有这些值已被设置。

基本上是这样的。

public static bool OnlyTheseFlagsSet<T>(this T input, params T[] values) where T : struct, IConvertible 
{ 
} 

我能想到这样做的唯一方法是让它们设置所有可用的枚举值检查和确认仅供两人一直。

是否有另一种方法来解决这个问题,使用某种按位操作?

+0

这是一门功课?为什么T约束一个结构而不是枚举? – LightStriker

+0

哈哈,那真是令人尴尬。不,只是没有对位操作的牢固掌握......这是一个真正的需求 –

+0

试着将它约束到Enum并看看会发生什么。 ; -p –

回答

5

对所有需要的标志执行“或”并与输入进行比较 - 应该相等。类似下面,用正确的循环计算左侧值:

var onlyTheseFlagsSet = (value[0] | value[1]) == input; 
0

我缺少的东西还是会不只是和PARAMS T []值和检查,如果输入等于结果?
如果你只想要那些标志而没有其他标志,输入应该等于那些标志的总和。

+1

因为'+'可能会很危险,因为即使对于标志类型,Enum值也不必互相排斥 - 需要使用或'|'来正确合并标志。 –

1

这将翻转每个输入值的位。如果只设置了这些值,则结果值将为零。否则,如果该值未在input中设置,则会将位翻转为1,这将使值不为零。

public static bool OnlyTheseFlagsSet<T>(this T input, params T[] values) where T : struct, IConvertible 
{ 
    int enumVal = input.ToInt32(null); 

    foreach (T itm in values) 
    { 
     int val = itm.ToInt32(null); 
     enumVal = enumVal^val;     
    } 

    return (enumVal == 0); 
} 
+1

+1。我喜欢'''方法,但这个也很有趣。附注 - 请避免使用“itm”而不是“item”。 –

+0

我更喜欢'|'方法。同意变量名称,我只保留原作者的风格。 –

+0

备注:刚才注意到 - 你的代码依赖于值互斥......即使对于标记为标志的Enum值,也不是必须的。 –

0

假设您可以将输入转化为一个枚举:

foreach(MyFlags flag in values) 
    if (!input.HasFlag(flag)) 
     return false; 

return true; 

是的,我很懒这样。

+0

我认为OP还希望确保其他标志未设置...等待OP的评论... –

2

排他性要求意味着

input = values[0] | values[1] | ... | values[values.Length - 1]

所以,这里是你实现:

return input.ToInt32(null) == values.Aggregate(0, 
     (total, next) => total | next.ToInt32(null)); 
+0

+1。 '.ToInt32(null)'看起来很奇怪,但仍然有效! –