C#已标记的枚举:如何附加值

时间:2016-08-17 20:12:36

标签: c# enums

所以,我有一个标记的枚举:

 [Flags]
    public enum EmailResult
    {
        ISPUSuccess = 1,
        STSSuccess = 2
    }

我想要做的是,通过条件,将枚举变量设置为一个,另一个或两者。

如同,

If (ISPU){
    Result = EmailResult.ISPUSuccess
}
If (STS){
    Result += EmailResult.STSSuccess
}

喜欢添加..所以它实际上是

Result = EmailResult.ISPUSuccess | EmailResult.STSSuccess

3 个答案:

答案 0 :(得分:1)

使用标记时,您应该使用|(或|=)。想象

 Result = EmailResult.ISPUSuccess;

 if (someCondition)
   Result |= EmailResult.STSSuccess; 

 if (someOtherCondition)
   Result |= EmailResult.STSSuccess; 

如果someConditionsomeOtherCondition true都是1 | 2 | 2 == 3 == 11 (binary) ,您将获得正确的结果:

+=

如果是 Result = EmailResult.ISPUSuccess; if (someCondition) Result += EmailResult.STSSuccess; if (someOtherCondition) Result += EmailResult.STSSuccess;

1 + 2 + 2 == 5 == 101 (binary) 

你会有

101

错误(请注意,SELECT `id`,`name`, (SELECT count(*) FROM `tags_r` WHERE tag_id = `t`.`id`) as count FROM `tags` AS `t` 中的第二个位现在重置)。

答案 1 :(得分:1)

您可以使用|= operator在标有[Flags]属性的枚举中设置值。

[Flags]
public enum EmailResult
{
    None = 0,
    ISPUSuccess = 1,
    STSSuccess = 2
}

EmailResult result = EmailResult.None;

if(.... your condition ....)
   result |= EmailResult.ISPUSuccess;

if( .... other condition ...)
   result |= EmailResult.STSSuccess;

Console.WriteLine(result); // -> ISPUSuccess, STSSuccess

if((result & EmailResult.STSSuccess) != EmailResult.None)
   ..... flag is set ...

请注意,我已经添加了另一个值为0的枚举,以便在需要检查特定标志的当前状态的情况下使用。

答案 2 :(得分:0)

我使用以下通用结构来处理枚举:

/// <summary>
///     This helper allows for easier manipulation of <see cref="Enum" /> objects with the <see cref="FlagsAttribute" />.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
    MessageId = "Flags",
    Justification = "This struct acts as a wrapper around Enum Flags, and relates to the term in question.")]
public struct Flags<T> : IEquatable<Flags<T>>, IEquatable<T>
{
    #region Fields
    private T _value;
    #endregion

    #region Constructors
    /// <summary>
    ///     This constructor assures that the generic type of <typeparamref name="T" /> is first valid flags enum type.
    /// </summary>
    /// <exception cref="ArgumentException">Thrown if the type of <typeparamref name="T" /> is not a valid flag enum type.</exception>
    [SuppressMessage("Microsoft.Usage", "CA2207:InitializeValueTypeStaticFieldsInline",
        Justification = "This static constructor is not initializing any field values, instead, it is performing Type validation on the generic type T that cannot be otherwise performed.")]
    [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
        MessageId = "DMFirmy.Library.Core.Utilities.Throw.InvalidArgumentIf(System.Boolean,System.String,System.String)",
        Justification = "This library will not be localized.")]
    static Flags()
    {
        var type = typeof(T);
        Throw.InvalidArgumentIf(!type.IsEnum, "Flags<T> can only be used with enum types", nameof(T));
        Throw.InvalidArgumentIf(type.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0, "Flags<T> can only be used with enum types with the Flags attribute", nameof(T));
    }

    private Flags(T value)
    {
        _value = value;
    }
    #endregion

    #region Properties
    private long ValueInLong
    {
        get { return GetLongValue(_value); }
        set { _value = (T)Enum.ToObject(typeof(T), value); }
    }

    /// <summary>
    ///     Gets an enumerable collection of each of the individual flags that compose this instance.
    /// </summary>
    public IEnumerable<T> AllFlags
    {
        get
        {
            var values = (T[])Enum.GetValues(typeof(T));
            // ReSharper disable once LoopCanBeConvertedToQuery
            foreach (var f in values)
            {
                if (this[f]) yield return f;
            }
        }
    }
    #endregion

    #region Indexers
    /// <summary>
    ///     This indexer is used to add or check values within the stored flags.
    /// </summary>
    /// <param name="flags">The flags to search for.</param>
    /// <returns>True if the flag is contained, flase otherwise.</returns>
    [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
        MessageId = "flags",
        Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
    [IndexerName("Item")]
    public bool this[T flags]
    {
        get
        {
            var flagsInLong = GetLongValue(flags);
            return (ValueInLong & flagsInLong) == flagsInLong;
        }
        set
        {
            var flagsInLong = GetLongValue(flags);

            if(value)
            {
                ValueInLong |= flagsInLong;
            }
            else
            {
                ValueInLong &= ~flagsInLong;
            }
        }
    }
    #endregion

    #region Methods
    /// <summary>
    ///     Returns true if the given <paramref name="flags" /> are completely contained.
    /// </summary>
    /// <param name="flags">The flags to check that the underlying value contains.</param>
    /// <returns></returns>
    [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
        MessageId = "flags",
        Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
    public bool Contains(T flags)
    {
        return this[flags];
    }

    [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
        MessageId = "flags",
        Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
    [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider",
        MessageId = "System.Convert.ToInt64(System.Object)",
        Justification = "This library will not be localized.")]
    private static long GetLongValue(T flags)
    {
        return Convert.ToInt64(flags);
    }

    /// <summary>
    ///     Indicates whether this instance and first specified object are equal.
    /// </summary>
    /// <param name="obj">Another object to compare to.</param>
    /// <returns>
    ///     <c>true</c> if <paramref name="obj" /> and this instance are the same type and represent the same value;
    ///     otherwise, <c>false</c>.
    /// </returns>
    public override bool Equals(object obj)
    {
        // ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull
        if(obj is T)
        {
            return Equals((T)obj);
        }

        if(obj is Flags<T>)
        {
            return Equals((Flags<T>)obj);
        }

        return false;
    }

    /// <summary>
    ///     Indicates whether the current object is equal to another object of the same type.
    /// </summary>
    /// <param name="other">An object to compare with this object.</param>
    /// <returns><c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.</returns>
    public bool Equals(Flags<T> other)
    {
        return Equals(other._value);
    }

    /// <summary>
    ///     Indicates whether the current object is equal to another object of the same type.
    /// </summary>
    /// <param name="other">An object to compare with this object.</param>
    /// <returns><c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.</returns>
    public bool Equals(T other)
    {
        return Equals(_value, other);
    }

    /// <summary>
    ///     Returns the hash code for this instance.
    /// </summary>
    /// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
    public override int GetHashCode()
    {
        // ReSharper disable once NonReadonlyMemberInGetHashCode
        return _value.GetHashCode();
    }

    /// <summary>
    ///     Returns the string representation of the underlying value.
    /// </summary>
    /// <returns>The string representation of the underlying value</returns>
    public override string ToString()
    {
        return _value.ToString();
    }
    #endregion

    #region Operators
    /// <summary>
    ///     Implicit conversion from <see cref="Flags{T}" /> to the underlying <typeparamref name="T" /> value.
    /// </summary>
    /// <param name="flags">The <see cref="Flags{T}" /> value.</param>
    /// <returns>
    ///     The <typeparamref name="T" /> value represented by <paramref name="flags" />
    /// </returns>
    [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
        MessageId = "flags",
        Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
    public static implicit operator T(Flags<T> flags)
    {
        return flags._value;
    }

    /// <summary>
    ///     Implicit conversion from the underlying <typeparamref name="T" /> to first <see cref="Flags{T}" /> value.
    /// </summary>
    /// <param name="flags">The <typeparamref name="T" /> value.</param>
    /// <returns>The value of <paramref name="flags" /> as first <see cref="Flags{T}" />.</returns>
    [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
        MessageId = "flags",
        Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
    public static implicit operator Flags<T>(T flags)
    {
        return new Flags<T>(flags);
    }

    /// <summary>
    ///     Compares two <see cref="Flags{T}" /> instances to determine if they have equal values.
    /// </summary>
    /// <param name="first">The first <see cref="Flags{T}" />.</param>
    /// <param name="second">The second <see cref="Flags{T}" />.</param>
    /// <returns><c>true</c> if <paramref name="first" /> and <paramref name="second" /> are equal, <c>false</c> otherwise.</returns>
    public static bool operator ==(Flags<T> first, Flags<T> second)
    {
        return first.Equals(second);
    }

    /// <summary>
    ///     Compares two <see cref="Flags{T}" /> instances to determine if they do not have equal values.
    /// </summary>
    /// <param name="first">The first <see cref="Flags{T}" />.</param>
    /// <param name="second">The second <see cref="Flags{T}" />.</param>
    /// <returns>
    ///     <c>true</c> if <paramref name="first" /> and <paramref name="second" /> are not equal, <c>false</c> if they
    ///     are.
    /// </returns>
    public static bool operator !=(Flags<T> first, Flags<T> second)
    {
        return !(first == second);
    }
    #endregion
}

这个结构允许你使用你的标志枚举,就像索引的可枚举:

[Flags]
enum MyFlags
{
    None = 0,
    Value1 = 1,
    Value2 = 2,
    Value3 = 4
}

Flags<MyFlags> flags = MyFlags.Value1 | MyFlags.Value3;

bool hasValue1 = flags[MyFlags.Value1]; // true
bool hasValue2 = flags[MyFlags.Value2]; // false
bool hasValue3 = flags[MyFlags.Value3]; // true

flags[MyFlags.Value2] = true;
flags[MyFlags.Vlaue1] = false;

hasValue1 = flags[MyFlags.Value1]; // false
hasValue2 = flags[MyFlags.Value2]; // true
hasValue3 = flags[MyFlags.Value3]; // true

bool containsFlag = flags.Contains(MyFlags.Value2 | MyFlags.Value3); // true