Изобретая типичную функцию «Получить ближайшее значение перечисления», чтобы включить комбинации флагов

1

СЦЕНАРИЙ

Я работаю с 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)
//=======================================================
  • 0
    Откуда берется 10, что вы хотите использовать его как FileAttr, но он уже не представляет фактическую комбинацию флагов?
  • 0
    10 - это мнимое значение, переданное функции, которую я хотел бы сделать: GetNearestValue(Of FileAttributes)(10)
Показать ещё 4 комментария
Теги:
enums

1 ответ

2
Лучший ответ

Могут быть другие способы сделать это, но здесь одно возможное решение.

Начните с базового значения перечисления флагов (например, 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

  • 0
    Огромное спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню