C# 使用标志方法扩展枚举?
我找到了一些很好的例子,介绍了如何创建扩展方法来从按位枚举中读取单个值。但是现在C#4已经添加了HasFlag方法,它们真的不需要了。C# 使用标志方法扩展枚举?,c#,enums,extension-methods,bit-manipulation,bitflags,C#,Enums,Extension Methods,Bit Manipulation,Bitflags,我找到了一些很好的例子,介绍了如何创建扩展方法来从按位枚举中读取单个值。但是现在C#4已经添加了HasFlag方法,它们真的不需要了。 不过,我认为真正有帮助的是设置一个标志的扩展 在许多情况下,我需要单独设置标志值。 我想要一个具有此签名的扩展方法: enumVariable.SetFlag(EnumType.SingleFlag, true); 或者可能: enumVariable.SetFlag<EnumType>(EnumType.SingleFlag, true);
不过,我认为真正有帮助的是设置一个标志的扩展
在许多情况下,我需要单独设置标志值。
我想要一个具有此签名的扩展方法:
enumVariable.SetFlag(EnumType.SingleFlag, true);
或者可能:
enumVariable.SetFlag<EnumType>(EnumType.SingleFlag, true);
enumVariable.SetFlag(EnumType.SingleFlag,true);
您可能需要为每个枚举实现该方法,因为您不能以这种方式约束枚举:
public static T SetFlag<T>(this T @this, T flag, Boolean state) where T : enum { ... }
我不确定你的问题是什么,但如果你问这是否可能,我不得不说它不可能,没有这个确切的语法 枚举是值类型,因此按值传递。因此,接收枚举值的方法(如SetFlag)将接收枚举值的副本。即使它设置了一个标志,该更改也将局限于方法范围,而不是它所调用的枚举 您可以将它传递给带有
ref
修饰符的方法,如下所示:SetFlag(ref enumVariable,EnumType.SingleFlag)
,但据我所知,这不支持作为扩展方法
您可以创建一个通用枚举帮助器类:
public static class EnumHelper
{
public void SetFlag<TEnum>(ref TEnum enumValue, TEnum flag)
{
enumValue = enumValue | flag;
}
}
公共静态类EnumHelper
{
公共无效设置标志(参考TEnum枚举值,TEnum标志)
{
enumValue=enumValue |标志;
}
}
或者,也可以创建一个SetFlag方法,该方法返回一个新值,而不是修改现有变量
public static TEnum SetFlag<TEnum>(this TEnum enumValue, TEnum flag)
{
return enumValue | flag;
}
公共静态TEnum设置标志(此TEnum枚举值,TEnum标志)
{
返回枚举值|标志;
}
也许没有你希望的那么漂亮,但你可以很简单地做到:)
今天我找到了一个解决方案。谢谢雨果!优秀的代码,工作良好。我稍微调整了它,并将其添加到现有的EnumExtender中:
public static class EnumExtender
{
/// <summary>
/// Adds a flag value to enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.AddFlag(CustomEnumType.Value1);
/// </summary>
public static T AddFlag<T>(this Enum type, T enumFlag)
{
try
{
return (T)(object)((int)(object)type|(int)(object)enumFlag);
}
catch(Exception ex)
{
throw new ArgumentException(string.Format("Could not append flag value {0} to enum {1}",enumFlag, typeof(T).Name), ex);
}
}
/// <summary>
/// Removes the flag value from enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.RemoveFlag(CustomEnumType.Value1);
/// </summary>
public static T RemoveFlag<T>(this Enum type, T enumFlag)
{
try
{
return (T)(object)((int)(object)type & ~(int)(object)enumFlag);
}
catch (Exception ex)
{
throw new ArgumentException(string.Format("Could not remove flag value {0} from enum {1}", enumFlag, typeof(T).Name), ex);
}
}
/// <summary>
/// Sets flag state on enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.SetFlag(CustomEnumType.Value1, true);
/// </summary>
public static T SetFlag<T>(this Enum type, T enumFlag, bool value)
{
return value ? type.AddFlag(enumFlag) : type.RemoveFlag(enumFlag);
}
/// <summary>
/// Checks if the flag value is identical to the provided enum.
/// </summary>
public static bool IsIdenticalFlag<T>(this Enum type, T enumFlag)
{
try
{
return (int)(object)type == (int)(object)enumFlag;
}
catch
{
return false;
}
}
/// <summary>
/// Convert provided enum type to list of values.
/// This is convenient when you need to iterate enum values.
/// </summary>
public static List<T> ToList<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException();
var values = Enum.GetNames(typeof(T));
return values.Select(value => value.ToEnum<T>()).ToList();
}
/// <summary>
/// Present the enum values as a comma separated string.
/// </summary>
public static string GetValues<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException();
var values = Enum.GetNames(typeof(T));
return string.Join(", ", values);
}
}
公共静态类EnumExtender
{
///
///将标志值添加到枚举。
///请注意,枚举是值类型,因此需要处理此方法返回的值。
///示例:myEnumVariable=myEnumVariable.AddFlag(CustomEnumType.Value1);
///
公共静态T AddFlag(此枚举类型,T enumFlag)
{
尝试
{
返回(T)(对象)((int)(对象)类型|(int)(对象)枚举标志);
}
捕获(例外情况除外)
{
抛出新的ArgumentException(string.Format(“无法将标志值{0}附加到枚举{1}”)、enumFlag、typeof(T.Name)、ex;
}
}
///
///从枚举中删除标志值。
///请注意,枚举是值类型,因此需要处理此方法返回的值。
///示例:myEnumVariable=myEnumVariable.RemoveFlag(CustomEnumType.Value1);
///
公共静态T RemoveFlag(此枚举类型,T enumFlag)
{
尝试
{
返回(T)(对象)((int)(对象)类型和~(int)(对象)枚举标志);
}
捕获(例外情况除外)
{
抛出新的ArgumentException(string.Format(“无法从枚举{1}中删除标志值{0}”)、enumFlag、typeof(T.Name)、ex;
}
}
///
///设置枚举上的标志状态。
///请注意,枚举是值类型,因此需要处理此方法返回的值。
///示例:myEnumVariable=myEnumVariable.SetFlag(CustomEnumType.Value1,true);
///
公共静态T SetFlag(此枚举类型、T enumFlag、bool值)
{
返回值?type.AddFlag(enumFlag):type.RemoveFlag(enumFlag);
}
///
///检查标志值是否与提供的枚举相同。
///
公共静态布尔IsIdenticalFlag(此枚举类型,T枚举标志)
{
尝试
{
返回(int)(对象)类型==(int)(对象)枚举标志;
}
抓住
{
返回false;
}
}
///
///将提供的枚举类型转换为值列表。
///这在需要迭代枚举值时非常方便。
///
公共静态列表ToList()
{
if(!typeof(T).IsEnum)
抛出新ArgumentException();
var values=Enum.GetNames(typeof(T));
返回值。选择(value=>value.ToEnum()).ToList();
}
///
///以逗号分隔的字符串形式显示枚举值。
///
公共静态字符串GetValues()
{
if(!typeof(T).IsEnum)
抛出新ArgumentException();
var values=Enum.GetNames(typeof(T));
返回字符串。Join(“,”,值);
}
}
我做了一些对我来说非常简单的事情。由于使用动态强制转换,可能效率不高。但也许你会喜欢它
public static T SetFlag<T>(this Enum value, T flag, bool set)
{
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
// note: AsInt mean: math integer vs enum (not the c# int type)
dynamic valueAsInt = Convert.ChangeType(value, underlyingType);
dynamic flagAsInt = Convert.ChangeType(flag, underlyingType);
if (set)
{
valueAsInt |= flagAsInt;
}
else
{
valueAsInt &= ~flagAsInt;
}
return (T)valueAsInt;
}
public static T SetFlag(此枚举值、T标志、bool集)
{
Type underyingtype=Enum.getunderyingtype(value.GetType());
//注:AsInt平均值:数学整数vs枚举(不是c#int类型)
动态值SINT=Convert.ChangeType(值,underyingType);
动态flagAsInt=Convert.ChangeType(标志,参考类型);
如果(设置)
{
valueAsInt |=flagAsInt;
}
其他的
{
valueAsInt&=~flagAsInt;
}
返回(T)值;
}
您为什么需要它?类似enumVariable=enumVariable | EnumType.SingleFlag的表达式;更简短,更容易阅读,尤其是当你需要设置多个标志时…呸,你是对的。遗憾的是,您不能将枚举用作泛型类型约束。您可以将约束设置为struct,这可能会有所帮助。不会有帮助,因为我仍然无法对它们使用|运算符。谢谢,这是我暂时做的。我想我应该坚持这一点。(@this^flag)
将设置枚举(如果未设置),这不是它在state==false时应该做的(@this&~标志)
是清除flag@Firo你是对的,在我的个人实现中它是正确的。它不是类型安全的。当然还有一点:如果一个解决方案对你有效,那么当你找到一个解决方案时,没有理由从帖子中删除分数
public static class EnumExtender
{
/// <summary>
/// Adds a flag value to enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.AddFlag(CustomEnumType.Value1);
/// </summary>
public static T AddFlag<T>(this Enum type, T enumFlag)
{
try
{
return (T)(object)((int)(object)type|(int)(object)enumFlag);
}
catch(Exception ex)
{
throw new ArgumentException(string.Format("Could not append flag value {0} to enum {1}",enumFlag, typeof(T).Name), ex);
}
}
/// <summary>
/// Removes the flag value from enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.RemoveFlag(CustomEnumType.Value1);
/// </summary>
public static T RemoveFlag<T>(this Enum type, T enumFlag)
{
try
{
return (T)(object)((int)(object)type & ~(int)(object)enumFlag);
}
catch (Exception ex)
{
throw new ArgumentException(string.Format("Could not remove flag value {0} from enum {1}", enumFlag, typeof(T).Name), ex);
}
}
/// <summary>
/// Sets flag state on enum.
/// Please note that enums are value types so you need to handle the RETURNED value from this method.
/// Example: myEnumVariable = myEnumVariable.SetFlag(CustomEnumType.Value1, true);
/// </summary>
public static T SetFlag<T>(this Enum type, T enumFlag, bool value)
{
return value ? type.AddFlag(enumFlag) : type.RemoveFlag(enumFlag);
}
/// <summary>
/// Checks if the flag value is identical to the provided enum.
/// </summary>
public static bool IsIdenticalFlag<T>(this Enum type, T enumFlag)
{
try
{
return (int)(object)type == (int)(object)enumFlag;
}
catch
{
return false;
}
}
/// <summary>
/// Convert provided enum type to list of values.
/// This is convenient when you need to iterate enum values.
/// </summary>
public static List<T> ToList<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException();
var values = Enum.GetNames(typeof(T));
return values.Select(value => value.ToEnum<T>()).ToList();
}
/// <summary>
/// Present the enum values as a comma separated string.
/// </summary>
public static string GetValues<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException();
var values = Enum.GetNames(typeof(T));
return string.Join(", ", values);
}
}
public static T SetFlag<T>(this Enum value, T flag, bool set)
{
Type underlyingType = Enum.GetUnderlyingType(value.GetType());
// note: AsInt mean: math integer vs enum (not the c# int type)
dynamic valueAsInt = Convert.ChangeType(value, underlyingType);
dynamic flagAsInt = Convert.ChangeType(flag, underlyingType);
if (set)
{
valueAsInt |= flagAsInt;
}
else
{
valueAsInt &= ~flagAsInt;
}
return (T)valueAsInt;
}