有没有更简单的方法将 int 解析为通用 Flags 枚举?
Is there an easier way to parse an int to a generic Flags enum?
我有一个通用函数可以将对象解析为通用枚举。
但是,在尝试将 int 安全地解析为 [Flags] 枚举时,我 运行 遇到了问题。
直接使用 Enum.ToObject() 可以解析有效组合,但如果没有标志组合,则只会 return 原始值。
此外,当标志组合没有明确的枚举成员时,Enum.ToName() 和 Enum.IsDefined() 不会 return 有用的值。
例如:
[Flags]
public enum Color
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
}
// Returns 20
Enum.ToObject(typeof(Color), 20)
// Returns ""
Enum.ToName(typeof(Color), 3)
// Returns false
Enum.IsDefined(typeof(Color), 3)
我编写了一个我认为在技术上可行的函数,但似乎必须有更好的方法来实现它。
我的函数:
public static T ParseEnumerator<T>(object parseVal, T defaultVal) where T : struct, IConvertible
{
Type ttype = typeof(T);
if (!ttype.IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
bool isFlag = ttype.GetCustomAttribute(typeof(FlagsAttribute)) != null;
try
{
if (parseVal == null)
{
return defaultVal;
}
else if (parseVal is T)
{
return (T)parseVal;
}
else if (parseVal is string)
{
return (T)Enum.Parse(ttype, parseVal.ToString(), true);
}
//**************** The section at issue **********************************/
else if (isFlag && parseVal is int)
{
List<string> flagsList = new List<string>();
int maxVal = 0;
//Loop through each bit flag
foreach (var val in Enum.GetValues(ttype))
{
if (CountBits((int)val) == 1)
{
if ((int)val > maxVal)
maxVal = (int)val;
// If the current bit is set, add the flag to the result
if (((int)parseVal & (int)val) == (int)val)
{
string enumName = Enum.GetName(ttype, val);
if (!string.IsNullOrEmpty(enumName))
flagsList.Add(enumName);
}
}
}
// Is the value being parsed over the highest bitwise value?
if ((int)parseVal >= (maxVal << 1))
return defaultVal;
else
return (T)Enum.Parse(ttype, string.Join(",", flagsList));
}
//************************************************************************/
else
{
string val = Enum.GetName(ttype, parseVal);
if (!string.IsNullOrEmpty(val))
return (T)Enum.ToObject(ttype, parseVal);
else
return defaultVal;
}
}
catch
{
return defaultVal;
}
}
有什么我想念的吗?还是有另一种方法可以安全地解析这些值?
感谢任何帮助,谢谢!
-MM
由于您的通用函数必须知道 Enum 类型才能开始,您可以只废弃该函数并改用基本转换。
using System;
namespace SO_58455415_enum_parsing {
[Flags]
public enum CheeseCharacteristics {
Yellow = 1,
Mouldy = 2,
Soft = 4,
Holed = 8
}
public static class Program {
static void Main(string[] args) {
CheeseCharacteristics cc = (CheeseCharacteristics)12;
Console.WriteLine(cc);
}
}
}
如果您只想知道是否有一个可以使用枚举标志创建的值..那很简单,只要我们可以假设每个标志都是 "sequential"(例如,有标志之间没有间隙)。介于 1 和所有标志值之和之间的所有数字都可以由标志的某种组合组成。您可以简单地将标志值加在一起并将其与您的问题值进行比较。
public static bool IsValidFlags<T>(int checkValue) where T:Enum {
int maxFlagValue = ((int[])Enum.GetValues(typeof(T))).Sum();
return (0 < checkValue) && (checkValue <= maxFlagValue);
}
为了将来参考,您可以将通用参数限制为枚举:
void fx<T> () where T:Enum { }
我有一个通用函数可以将对象解析为通用枚举。
但是,在尝试将 int 安全地解析为 [Flags] 枚举时,我 运行 遇到了问题。
直接使用 Enum.ToObject() 可以解析有效组合,但如果没有标志组合,则只会 return 原始值。
此外,当标志组合没有明确的枚举成员时,Enum.ToName() 和 Enum.IsDefined() 不会 return 有用的值。
例如:
[Flags]
public enum Color
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
}
// Returns 20
Enum.ToObject(typeof(Color), 20)
// Returns ""
Enum.ToName(typeof(Color), 3)
// Returns false
Enum.IsDefined(typeof(Color), 3)
我编写了一个我认为在技术上可行的函数,但似乎必须有更好的方法来实现它。
我的函数:
public static T ParseEnumerator<T>(object parseVal, T defaultVal) where T : struct, IConvertible
{
Type ttype = typeof(T);
if (!ttype.IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
bool isFlag = ttype.GetCustomAttribute(typeof(FlagsAttribute)) != null;
try
{
if (parseVal == null)
{
return defaultVal;
}
else if (parseVal is T)
{
return (T)parseVal;
}
else if (parseVal is string)
{
return (T)Enum.Parse(ttype, parseVal.ToString(), true);
}
//**************** The section at issue **********************************/
else if (isFlag && parseVal is int)
{
List<string> flagsList = new List<string>();
int maxVal = 0;
//Loop through each bit flag
foreach (var val in Enum.GetValues(ttype))
{
if (CountBits((int)val) == 1)
{
if ((int)val > maxVal)
maxVal = (int)val;
// If the current bit is set, add the flag to the result
if (((int)parseVal & (int)val) == (int)val)
{
string enumName = Enum.GetName(ttype, val);
if (!string.IsNullOrEmpty(enumName))
flagsList.Add(enumName);
}
}
}
// Is the value being parsed over the highest bitwise value?
if ((int)parseVal >= (maxVal << 1))
return defaultVal;
else
return (T)Enum.Parse(ttype, string.Join(",", flagsList));
}
//************************************************************************/
else
{
string val = Enum.GetName(ttype, parseVal);
if (!string.IsNullOrEmpty(val))
return (T)Enum.ToObject(ttype, parseVal);
else
return defaultVal;
}
}
catch
{
return defaultVal;
}
}
有什么我想念的吗?还是有另一种方法可以安全地解析这些值?
感谢任何帮助,谢谢!
-MM
由于您的通用函数必须知道 Enum 类型才能开始,您可以只废弃该函数并改用基本转换。
using System;
namespace SO_58455415_enum_parsing {
[Flags]
public enum CheeseCharacteristics {
Yellow = 1,
Mouldy = 2,
Soft = 4,
Holed = 8
}
public static class Program {
static void Main(string[] args) {
CheeseCharacteristics cc = (CheeseCharacteristics)12;
Console.WriteLine(cc);
}
}
}
如果您只想知道是否有一个可以使用枚举标志创建的值..那很简单,只要我们可以假设每个标志都是 "sequential"(例如,有标志之间没有间隙)。介于 1 和所有标志值之和之间的所有数字都可以由标志的某种组合组成。您可以简单地将标志值加在一起并将其与您的问题值进行比较。
public static bool IsValidFlags<T>(int checkValue) where T:Enum {
int maxFlagValue = ((int[])Enum.GetValues(typeof(T))).Sum();
return (0 < checkValue) && (checkValue <= maxFlagValue);
}
为了将来参考,您可以将通用参数限制为枚举:
void fx<T> () where T:Enum { }