我找到了很好的例子,说明如何创建扩展方法以从按位枚举中读出单个值。但是现在C#4已经添加了HasFlag方法,他们真的不需要它们
我认为真正有用的是设置单个标志的扩展!
我有很多情况需要单独设置标志值
我想要一个带有此签名的扩展方法:
enumVariable.SetFlag(EnumType.SingleFlag, true);
或者可能:
enumVariable.SetFlag<EnumType>(EnumType.SingleFlag, true);
答案 0 :(得分:3)
今天我在http://hugoware.net/blog/enums-flags-and-csharp找到了解决方案。谢谢雨果!优秀的代码,工作正常。我稍微调整了一下并将其添加到我现有的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);
}
}
答案 1 :(得分:3)
我做了一些对我有用的事情,非常简单。由于动态铸造使用可能效率不高。但也许你会喜欢它?
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;
}
答案 2 :(得分:2)
您可能需要为每个枚举实现该方法,因为您不能以这种方式约束枚举:
public static T SetFlag<T>(this T @this, T flag, Boolean state) where T : enum { ... }
无论如何,在泛型类型的C#中不允许运算符重载,因此不能在不进行转换的情况下使用泛型类型T.
所以你的扩展方法必须如下所示:
public static MyFlag SetFlag(this MyFlag @this, MyFlag flag, Boolean state)
{
return state ? (@this | flag) : (@this & ~flag);
}
答案 3 :(得分:2)
我不确定你的问题是什么,但如果你问这是否可行,我不得不说它不是,不是这个语法。
枚举是值类型,因此按值传递。因此,接收枚举值的方法(如SetFlag)将收到它的COPY。即使它设置了一个标志,该变化也将局限于方法范围,而不是它被调用的枚举。
您可以将其传递给使用ref
修饰符的方法,如下所示:SetFlag(ref enumVariable, EnumType.SingleFlag)
但据我所知,这不作为扩展方法支持。
你可以做的是创建一个通用的枚举助手类:
public static class EnumHelper
{
public void SetFlag<TEnum>(ref TEnum enumValue, TEnum flag)
{
enumValue = enumValue | flag;
}
}
或者,创建一个返回新值而不是修改现有变量的SetFlag方法。
public static TEnum SetFlag<TEnum>(this TEnum enumValue, TEnum flag)
{
return enumValue | flag;
}
答案 4 :(得分:2)
也许不像你希望的那么漂亮,但你可以很简单地做到这一点:)
enumVariable |= EnumType.SingleFlag;