using System; using System.Collections; using System.Collections.Generic; namespace Vanara.Extensions { /// Structure to use in place of a enumerated type with the set. Allows for indexer access to flags and simplifies boolean logic. /// An enumerated type. /// /// Use this structure by replacing an enumerated type field for simpler access. See old and new way examples below: /// var fileInfo = new FileInfo(@"C:\MyFile.txt"); /// FileAttributes fileAttr = fileInfo.Attributes; /// if ((fileAttr & FileAttributes.Hidden) != FileAttributes.Hidden) /// { /// Console.WriteLine("The file is hidden. Trying to unhide now."); /// fileInfo.Attributes = (fileAttr & ~FileAttributes.Hidden); /// } /// var fileInfo = new FileInfo(@"C:\MyFile.txt"); /// EnumFlagIndexer<FileAttributes> fileAttr = fileInfo.Attributes; /// if (fileAttr[FileAttributes.Hidden]) /// { /// Console.WriteLine("The file is hidden. Trying to unhide now."); /// fileAttr[FileAttributes.Hidden] = false; /// fileInfo.Attributes = fileAttr; /// } /// public struct EnumFlagIndexer : IEquatable, IEquatable>, IEnumerable where TEnum : System.Enum { private TEnum flags; /// Initializes a new instance of the struct. /// The initial value. Defaults to default(E). public EnumFlagIndexer(TEnum initialValue) { if (!typeof(TEnum).IsEnum) throw new ArgumentException($"Type '{typeof(TEnum).FullName}' is not an enum"); if (!Attribute.IsDefined(typeof(TEnum), typeof(FlagsAttribute))) throw new ArgumentException($"Type '{typeof(TEnum).FullName}' doesn't have the 'Flags' attribute"); flags = initialValue; } /// Gets or sets the specified flag. /// A boolean value representing the presence of the specified enumerated flag. /// A value in the enumerated type to check. /// true if the flag is set; false otherwise. public bool this[TEnum flag] { get => (Convert.ToInt64(flags) & Convert.ToInt64(flag)) != 0; set { var flagsValue = Convert.ToInt64(flags); var flagValue = Convert.ToInt64(flag); if (value) flagsValue |= flagValue; else flagsValue &= ~flagValue; flags = (TEnum)Enum.ToObject(typeof(TEnum), flagsValue); } } /// Implements the operator !=. /// An instance of . /// An instance of the enumerated type. /// The result of the operator. public static bool operator !=(EnumFlagIndexer a, TEnum b) => !a.Equals(b); /// Implements the operator &. /// An instance of . /// An instance of the enumerated type. /// The result of the operator. public static TEnum operator &(EnumFlagIndexer a, TEnum b) => (TEnum)Enum.ToObject(typeof(TEnum), Convert.ToInt64(a.flags) & Convert.ToInt64(b)); /// Implements the operator |. /// An instance of . /// An instance of the enumerated type. /// The result of the operator. public static TEnum operator |(EnumFlagIndexer a, TEnum b) => (TEnum)Enum.ToObject(typeof(TEnum), Convert.ToInt64(a.flags) | Convert.ToInt64(b)); /// Implements the operator ==. /// An instance of . /// An instance of the enumerated type. /// The result of the operator. public static bool operator ==(EnumFlagIndexer a, TEnum b) => a.Equals(b); /// Implicitly converts an instance of to the value of enumerated type E. /// The f. /// The result of the operator. public static implicit operator TEnum(EnumFlagIndexer f) => f.flags; /// Implicitly converts a value of E to an instance of . /// The e. /// The result of the operator. public static implicit operator EnumFlagIndexer(TEnum e) => new EnumFlagIndexer(e); /// Clears and sets to default(E). public void Clear() { flags = default; } /// Indicates whether the current object is equal to another object of the same type. /// An object to compare with this object. /// true if the current object is equal to the parameter; otherwise, false. public bool Equals(TEnum other) => Convert.ToInt64(flags) == Convert.ToInt64(other); /// Indicates whether the current object is equal to another object of the same type. /// An object to compare with this object. /// true if the current object is equal to the parameter; otherwise, false. public bool Equals(EnumFlagIndexer other) => Convert.ToInt64(flags) == Convert.ToInt64(other.flags); /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public override bool Equals(object obj) => Equals(obj, flags); /// Returns a hash code for this instance. /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() => flags.GetHashCode(); /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// Returns an enumerator that iterates through the collection. /// A that can be used to iterate through the collection. public IEnumerator GetEnumerator() { long t = 0; foreach (TEnum e in Enum.GetValues(typeof(TEnum))) if (this[e]) { t |= Convert.ToInt64(e); yield return e; } var rem = Convert.ToInt64(flags) ^ t; if (rem != 0) yield return (TEnum)Enum.ToObject(typeof(TEnum), rem); } /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() => flags.ToString(); /// Unions the specified flags. /// The flags. public void Union(TEnum enumVal) { this[enumVal] = true; } /// Unions the specified flags. /// The flags. public void Union(IEnumerable enumValues) { foreach (var e in enumValues) this[e] = true; } } }