Разбор флагов перечисления из списка или целого числа через запятую
У меня есть XML, который содержит несколько флагов, некоторые из них являются 32-разрядными целыми числами без знака, а другие являются 64-разрядными целыми числами без знака. Некоторые из них написаны в списке через запятую, а другие в шестнадцатеричном стиле.
Смотрите этот пример:
<Color>Blue,Red</Color>
<Color>0xC</Color>
Поскольку я не хочу писать метод для анализа каждого перечисления, я решил использовать универсальный метод. Но Visual Studio не позволит мне построить решение. Вот мой метод:
public static T ParseFlags<T>(string value) where T : struct
{
T result = (T)((object)0);
string[] array;
// Remove white spaces and delimit string if it is comma-separated
if (ParseDelimitedString(value, ',', out array))
{
for (int i = 0; i < array.Length; i++)
{
T flag = (T)((object)0);
// Check if value is member of enumeration
if (Enum.TryParse<T>(array[i], out flag))
{
result |= (T)((object)flag);
}
}
}
else
{
switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))))
{
// Remove hex characters and parse node's inner text
case TypeCode.UInt32:
result = (T)((object)ParseUint(value));
break;
case TypeCode.UInt64:
result = (T)((object)ParseUlong(value));
break;
}
}
return result;
}
Я получаю сообщение об ошибке:
Ошибка 1 Оператор '|=' не может быть применен к операндам типа 'T' и 'T'
Есть ли способ сделать это?
4 ответа
Вы делаете много работы, которая может быть сделана для вас. Например, если ваш enum
объявлен с FlagsAttribute
затем Enum.Parse
проанализирует для вас значения, разделенные запятыми.
public static T ParseFlags<T>(string value) where T : struct
{
T result;
ulong temp;
if (Enum.TryParse(value, out result))
{
return result;
}
string hexNum = value.StartsWith("0x") ? value.Substring(2) : value;
if (ulong.TryParse(hexNum, NumberStyles.HexNumber, null, out temp))
{
return (T)Enum.ToObject(typeof(T), temp);
}
throw new ArgumentException("value could not be parsed");
}
Я проверил это с различными типами перечислений Flags с short
, int
, а также ulong
поддерживающие ценности.
Если вы знаете, какой тип enum вы анализируете:
[Fact]
public void when_parsing_options_then_can_combine_flags()
{
var values = "Singleline | Compiled";
var options = values.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.Select(value => (RegexOptions)Enum.Parse(typeof(RegexOptions), value))
.Aggregate(RegexOptions.None, (current, value) => current |= value);
Assert.Equal(RegexOptions.Singleline | RegexOptions.Compiled, options);
}
Использование "|=" в этом фрагменте заставляет меня думать, что вы хотели использовать Enum в качестве набора битов, а не просто старый Enum. Если это так, вы должны внести небольшое изменение - объявите локальный "результат" как int и соответствующим образом скорректировать приведение, тогда ваш оператор return должен быть "return (T)(object)result;"). Эта строка с "|" будет выглядеть так: "result |= (int)(object)flag;". Возможно, есть лучший ответ, но обратите внимание, что перечисления являются целыми числами, и ваш сценарий набора битов достаточно хорошо охватывается этим решением, если только не возникли ситуации, которые я пропустил или вы не указали.
Попробуй это:
public static T ParseFlags<T>(string value) where T : struct
{
long result = 0L;
string[] array;
// Remove white spaces and delimit string if it is comma-separated
if (ParseDelimitedString(value, ',', out array))
{
for (int i = 0; i < array.Length; i++)
{
T flag = default(T);
// Check if value is member of enumeration
if (Enum.TryParse<T>(array[i], out flag))
{
result |= (long)flag;
}
}
}
else
{
switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))))
{
// Remove hex characters and parse node's inner text
case TypeCode.UInt32:
result = ParseUint(value);
break;
case TypeCode.UInt64:
result = ParseUlong(value);
break;
}
}
return (T)((object)result);
}
Надеюсь, поможет.