2

ビット単位の列挙型から単一の値を読み取る拡張メソッドを作成する方法の良い例を見つけました。しかし、C#4でHasFlagメソッドが追加されたので、実際には必要ありません。

単一のフラグを設定するための拡張機能ですが、私が本当に役立つと思うのは!
フラグ値を個別に設定する必要がある状況はたくさんあります。
この署名を使用した拡張メソッドが必要です。

enumVariable.SetFlag(EnumType.SingleFlag, true);

またはおそらく:

enumVariable.SetFlag<EnumType>(EnumType.SingleFlag, true);
4

5 に答える 5

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

}
于 2012-05-04T13:02:21.870 に答える
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;
}
于 2014-02-06T14:13:11.307 に答える
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;
}
于 2012-02-09T08:47:39.777 に答える
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);
}
于 2012-02-09T08:43:52.263 に答える
2

思ったほどきれいではないかもしれませんが、とても簡単にできます :)

enumVariable |= EnumType.SingleFlag;
于 2012-02-09T08:51:57.240 に答える