#c# #.net #enums
#c# #.net #перечисления
Вопрос:
Я использую атрибут enum with flags как способ отслеживания статуса.
Примером является следующее:
Created = 1
Completed = 2
Dispatched = 4
Не записывая ничего слишком жесткого (если проверьте это, сделайте это, если проверьте это, сделайте это), я хочу иметь возможность найти самый высокий флаг, который был установлен таким образом в этом примере:
Item.Status = Status.Created | Status.Completed
мифический метод вернул бы 2 — как завершенный, это флаг, установленный с наибольшим значением.
GetMaxSetFlagValue(Item.Status) // returns 2
Я нашел вопросы, которые вращались вокруг фактического перечисления, а не значения, которое использует флаги. Я уверен, что этого можно достичь с помощью Linq …?
Ответ №1:
Должно сработать что-то вроде следующего:
static int GetMaxSetFlagValue<T>(T flags) where T : struct
{
int value = (int)Convert.ChangeType(flags, typeof(int));
IEnumerable<int> setValues = Enum.GetValues(flags.GetType()).Cast<int>().Where(f => (f amp; value) == f);
return setValues.Any() ? setValues.Max() : 0;
}
Метод завершится ошибкой, если T не является типом перечисления, поэтому проверку предпочтительно выполнять в начале метода. Также это не будет работать для перечисления с базовым типом, большим, чем int
(т. Е. long
).
Ответ №2:
Это метод расширения, который я использую. Это вернет вам перечисление обратно
var maxStatus = Item.Status.GetFlags().Max();
Вывод: maxStatus = Завершено
public static class EnumExtensions {
/// <summary>Enumerates get flags in this collection.</summary>
///
/// <param name="value">The value.
/// </param>
///
/// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns>
public static IEnumerable<T> GetFlags<T> (this T value) where T : struct {
return GetFlags (value, Enum.GetValues (value.GetType ()).Cast<T> ().ToArray ());
}
/// <summary>Enumerates get flags in this collection.</summary>
///
/// <param name="value"> The value.
/// </param>
/// <param name="values">The values.
/// </param>
///
/// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns>
private static IEnumerable<T> GetFlags<T> (T value, T [] values) where T : struct {
if (!typeof (T).IsEnum) {
throw new ArgumentException ("Type must be an enum.");
}
ulong bits = Convert.ToUInt64 (value);
var results = new List<T> ();
for (int i = values.Length - 1; i >= 0; i--) {
ulong mask = Convert.ToUInt64 (values [i]);
if (i == 0 amp;amp; mask == 0L)
break;
if ((bits amp; mask) == mask) {
results.Add (values [i]);
bits -= mask;
}
}
if (bits != 0L)
return Enumerable.Empty<T> ();
if (Convert.ToUInt64 (value) != 0L)
return results.Reverse<T> ();
if (bits == Convert.ToUInt64 (value) amp;amp; values.Length > 0 amp;amp; Convert.ToUInt64 (values [0]) == 0L)
return values.Take (1);
return Enumerable.Empty<T> ();
}
}
Ответ №3:
Поскольку вы можете выполнять обратное преобразование в uint, вы могли бы использовать:
public uint LowestBit(uint x)
{
return ~(xamp;x-1)amp;x;
}
public uint HighestBit(uint x)
{
uint last = x;
while (x!=0)
{
last=x;
xamp;=x-1;
}
return last;
}