Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用标志方法扩展枚举?_C#_Enums_Extension Methods_Bit Manipulation_Bitflags - Fatal编程技术网

C# 使用标志方法扩展枚举?

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);

我找到了一些很好的例子,介绍了如何创建扩展方法来从按位枚举中读取单个值。但是现在C#4已经添加了HasFlag方法,它们真的不需要了。

不过,我认为真正有帮助的是设置一个标志的扩展
在许多情况下,我需要单独设置标志值。
我想要一个具有此签名的扩展方法:

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;
}