Я работаю с Enum
с набором FlagsAttribute
, для этого вопроса я приведу в качестве примера перечисление System.IO.FileAttributes
.
Давая значение, я хотел бы получить ближайшее значение в Enum
включая комбинации флагов.
Например, давая значение 10, ближайшее значение в перечислении выше 4, которое является FileAttributes.System
.
Но если мы включим комбинации флагов, то ближайшее значение должно быть 7, которое является FileAttributes.ReadOnly, FileAttributes.Hidden, FileAttributes.System
.
Я не претендую на изобретательность колеса, я просто хотел бы улучшить это, чтобы принять во внимание возможные комбинации флагов.
Затем, в С# или VB.Net, как я мог написать функцию " Получить ближайшую функцию- флажок-комбинацию "?
Это то, что я обычно использую, чтобы получить ближайшее значение Enum
, это не учитывает комбинации флагов.
Я написал эту функцию, ожидая, что это работает для коротких /ushort/integer/uinteger/long/ulong перечислений, но к моменту, когда я не тестировал ее во всех сценариях.
VB.Net:
''' <summary>
''' Gets the nearest value of an <see cref="T:Enum"/>.
''' </summary>
Private Function GetNearestEnumValue(Of T)(ByVal value As Long) As T
Return (From enumValue As T
In [Enum].GetValues(GetType(T)).Cast(Of T)()
Order By Math.Abs(value - Convert.ToInt64(enumValue))
).First
End Function
С# онлайн-перевод:
/// <summary>
/// Gets the nearest value of an <see cref="T:Enum"/>.
/// </summary>
private T GetNearestEnumValue<T>(long value)
{
return (from enumValue in Enum.GetValues(typeof(T)).Cast<T>()orderby Math.Abs(value - Convert.ToInt64(enumValue))).First;
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================
Могут быть другие способы сделать это, но здесь одно возможное решение.
Начните с базового значения перечисления флагов (например, Int32) и выполните цикл назад. Как только вы нажмете действительный флаг, сохраните его. Повторите то же самое, но на этот раз вперед. Затем вы просто проверяете, какой из них ближайший. Я только реализовал подписанную целочисленную часть, поэтому я оставлю без знака часть для вас.
Imports System.IO
Imports System.Runtime.CompilerServices
Public Module EnumExtension
<Extension()>
Public Function GetNearest(Of TEnum As Structure)(ByVal flags As TEnum) As TEnum
'Get the enum type
Dim enumType As Type = GetType(TEnum)
'If it not an enum, throw(up)
If (Not enumType.IsEnum) Then
Throw New InvalidOperationException()
End If
'Check if the underlying type of the enum is a 8|16|32|64 bit signed integer:
If ({GetType(SByte), GetType(Int16), GetType(Int32), GetType(Int64)}.Contains(enumType.GetEnumUnderlyingType())) Then
'Cast the flags
Dim value As Int64 = CType(CType(flags, Object), Int64)
'Get all enum flags
Dim enumValues As IEnumerable(Of Int64) = (From item In [Enum].GetValues(enumType) Select CType(item, Int64))
'Get the minimum flag value.
Dim minSum As Int64 = (From item In enumValues Order By item Ascending Select item).First()
'Sum all flags to get the highest possible value.
Dim maxSum As Int64 = enumValues.Sum()
'..
Dim lowerValue As Int64
Dim higherValue As Int64
Dim tempValue As TEnum = Nothing
'Get the nearest lower value
For lowerValue = value To minSum Step -1L
tempValue = CType([Enum].ToObject(enumType, lowerValue), TEnum)
If (tempValue.ToString() <> lowerValue.ToString()) Then
Exit For
End If
Next
'Get the nearest higher value
For higherValue = value To maxSum Step +1L
tempValue = CType([Enum].ToObject(enumType, higherValue), TEnum)
If (tempValue.ToString() <> higherValue.ToString()) Then
Exit For
End If
Next
Debug.WriteLine(String.Format("value: {0}, lower: {1}, higher: {2}", value, lowerValue, higherValue))
'Return the nearest value.
If ((value - lowerValue) <= (higherValue - value)) Then
Return CType([Enum].ToObject(enumType, lowerValue), TEnum)
Else
Return CType([Enum].ToObject(enumType, higherValue), TEnum)
End If
Else 'If 8|16|32|64 bit unsigned integer aka. (Byte, UInt16, UInt32, UInt64)
'Todo: work
End If
End Function
End Module
Контрольная работа:
Dim value As FileAttributes = CType(8202, FileAttributes)
Dim nearest As FileAttributes = value.GetNearest()
Debug.WriteLine("value: {0}, flags: {1}", CType(nearest, Integer), nearest.ToString())
Вывод:
значение: 8202, ниже: 8199, выше: 8208
value: 8199, flags: ReadOnly, Hidden, System, NotContentIndexed
10
- это мнимое значение, переданное функции, которую я хотел бы сделать:GetNearestValue(Of FileAttributes)(10)