确定枚举标志组合中包含的标志数量的最佳做法?
Best practice to determine the amount of flags contained in a Enum-flag combination?
在某些情况下,当我将 Enum 传递给方法时,我需要处理它是单个 Enum 值,还是标志组合,为此我写了这个简单的扩展:
Vb.Net:
<Extension>
Public Function FlagCount(ByVal sender As System.[Enum]) As Integer
Return sender.ToString().Split(","c).Count()
End Function
C#(在线翻译):
[Extension()]
public int FlagCount(this System.Enum sender) {
return sender.ToString().Split(',').Count();
}
用法示例:
Vb.Net:
Dim flags As FileAttributes = (FileAttributes.Archive Or FileAttributes.Compressed)
Dim count As Integer = flags.FlagCount()
MessageBox.Show(flagCount.ToString())
C#(在线翻译):
FileAttributes flags = (FileAttributes.Archive | FileAttributes.Compressed);
int count = flags.FlagCount();
MessageBox.Show(flagCount.ToString());
我只想问问是否存在一种比我目前正在做的更直接、更有效的方法来避免将标志组合表示为字符串然后拆分它。
选项A:
public int FlagCount(System.Enum sender)
{
bool hasFlagAttribute = sender.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute) // No flag attribute. This is a single value.
return 1;
var resultString = Convert.ToString(Convert.ToInt32(sender), 2);
var count = resultString.Count(b=> b == '1');//each "1" represents an enum flag.
return count;
}
解释:
- 如果枚举没有 "Flags attribute",则它必然是单个值。
- 如果枚举有"Flags attribute",将其转换为位表示并计算“1"s. each "1”代表一个枚举标志。
选项 B:
- 获取所有标记的项目。
- 数一数...
代码:
public int FlagCount(this System.Enum sender)
{
return sender.GetFlaggedValues().Count;
}
/// <summary>
/// All of the values of enumeration that are represented by specified value.
/// If it is not a flag, the value will be the only value returned
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
public static List<Enum> GetFlaggedValues(this Enum value)
{
//checking if this string is a flagged Enum
Type enumType = value.GetType();
object[] attributes = enumType.GetCustomAttributes(true);
bool hasFlags = enumType.GetCustomAttributes(true).Any(attr => attr is System.FlagsAttribute);
//If it is a flag, add all flagged values
List<Enum> values = new List<Enum>();
if (hasFlags)
{
Array allValues = Enum.GetValues(enumType);
foreach (Enum currValue in allValues)
{
if (value.HasFlag(currValue))
{
values.Add(currValue);
}
}
}
else//if not just add current value
{
values.Add(value);
}
return values;
}
放不下这个。计算整数中的位时的最佳做法是不要转换为字符串......
现在我们都使用高级语言,我们是否失去了使用位的能力? ;)
由于问题是关于最有效的实施,这里是我的答案。我没有尝试过对其进行超优化,因为我认为这样做会混淆它。我还使用以前的答案作为基础,以便更容易进行比较。
有两种方法,一种计算标志,另一种如果您只想知道它是否只有一个标志,则提前退出。
注意:您不能删除标志属性检查,因为标准的非标志枚举也可以是任何数字。
public static int FlagCount(this System.Enum enumValue){
var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute)
return 1;
var count = 0;
var value = Convert.ToInt32(enumValue);
while (value != 0){
if ((value & 1) == 1)
count++;
value >>= 1;
}
return count;
}
public static bool IsSingleFlagCount(this System.Enum enumValue){
var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute)
return true;
var isCounted = false;
var value = Convert.ToInt32(enumValue);
while (value != 0){
if ((value & 1) == 1){
if (isCounted)
return false;
isCounted = true;
}
value >>= 1;
}
return true;
}
在某些情况下,当我将 Enum 传递给方法时,我需要处理它是单个 Enum 值,还是标志组合,为此我写了这个简单的扩展:
Vb.Net:
<Extension>
Public Function FlagCount(ByVal sender As System.[Enum]) As Integer
Return sender.ToString().Split(","c).Count()
End Function
C#(在线翻译):
[Extension()]
public int FlagCount(this System.Enum sender) {
return sender.ToString().Split(',').Count();
}
用法示例:
Vb.Net:
Dim flags As FileAttributes = (FileAttributes.Archive Or FileAttributes.Compressed)
Dim count As Integer = flags.FlagCount()
MessageBox.Show(flagCount.ToString())
C#(在线翻译):
FileAttributes flags = (FileAttributes.Archive | FileAttributes.Compressed);
int count = flags.FlagCount();
MessageBox.Show(flagCount.ToString());
我只想问问是否存在一种比我目前正在做的更直接、更有效的方法来避免将标志组合表示为字符串然后拆分它。
选项A:
public int FlagCount(System.Enum sender)
{
bool hasFlagAttribute = sender.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute) // No flag attribute. This is a single value.
return 1;
var resultString = Convert.ToString(Convert.ToInt32(sender), 2);
var count = resultString.Count(b=> b == '1');//each "1" represents an enum flag.
return count;
}
解释:
- 如果枚举没有 "Flags attribute",则它必然是单个值。
- 如果枚举有"Flags attribute",将其转换为位表示并计算“1"s. each "1”代表一个枚举标志。
选项 B:
- 获取所有标记的项目。
- 数一数...
代码:
public int FlagCount(this System.Enum sender)
{
return sender.GetFlaggedValues().Count;
}
/// <summary>
/// All of the values of enumeration that are represented by specified value.
/// If it is not a flag, the value will be the only value returned
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
public static List<Enum> GetFlaggedValues(this Enum value)
{
//checking if this string is a flagged Enum
Type enumType = value.GetType();
object[] attributes = enumType.GetCustomAttributes(true);
bool hasFlags = enumType.GetCustomAttributes(true).Any(attr => attr is System.FlagsAttribute);
//If it is a flag, add all flagged values
List<Enum> values = new List<Enum>();
if (hasFlags)
{
Array allValues = Enum.GetValues(enumType);
foreach (Enum currValue in allValues)
{
if (value.HasFlag(currValue))
{
values.Add(currValue);
}
}
}
else//if not just add current value
{
values.Add(value);
}
return values;
}
放不下这个。计算整数中的位时的最佳做法是不要转换为字符串...... 现在我们都使用高级语言,我们是否失去了使用位的能力? ;)
由于问题是关于最有效的实施,这里是我的答案。我没有尝试过对其进行超优化,因为我认为这样做会混淆它。我还使用以前的答案作为基础,以便更容易进行比较。 有两种方法,一种计算标志,另一种如果您只想知道它是否只有一个标志,则提前退出。 注意:您不能删除标志属性检查,因为标准的非标志枚举也可以是任何数字。
public static int FlagCount(this System.Enum enumValue){
var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute)
return 1;
var count = 0;
var value = Convert.ToInt32(enumValue);
while (value != 0){
if ((value & 1) == 1)
count++;
value >>= 1;
}
return count;
}
public static bool IsSingleFlagCount(this System.Enum enumValue){
var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (!hasFlagAttribute)
return true;
var isCounted = false;
var value = Convert.ToInt32(enumValue);
while (value != 0){
if ((value & 1) == 1){
if (isCounted)
return false;
isCounted = true;
}
value >>= 1;
}
return true;
}