Возможно ли создать общий метод побитового перечисления 'IsOptionSet()'?

StackOverflow https://stackoverflow.com/questions/1614412

Вопрос

Приведенный ниже код упрощает передачу набора HtmlParserOptions, а затем проверяет один параметр, чтобы увидеть, был ли он выбран.

[Flags]
public enum HtmlParserOptions
{
    NotifyOpeningTags = 1,
    NotifyClosingTags = 2,
    NotifyText = 4,
    NotifyEmptyText = 8
}

private bool IsOptionSet(HtmlParserOptions options, HtmlParserOptions singleOption)
{
    return (options & singleOption) == singleOption;
}

Мой вопрос в том, возможно ли создать общую версию этого (я предполагаю, путем реализации интерфейса в свойствах метода), который будет работать с Любой перечисление с атрибутом Flags?

Это было полезно?

Решение

Редактировать:

Самый простой и приятный вариант - перейти на VS2010 Beta2 и использовать .NET 4 Перечисление.HasFlag способ.Команда фреймворка добавила много приятных дополнений к Enum, чтобы сделать их более удобными в использовании.


Оригинал (для текущего .NET):

Вы можете сделать это, передав Enum вместо generics:

static class EnumExtensions
{
    private static bool IsSignedTypeCode(TypeCode code)
    {
        switch (code)
        {
            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
                return false;
            default:
                return true;
        }
    }

    public static bool IsOptionSet(this Enum value, Enum option)
    {
        if (IsSignedTypeCode(value.GetTypeCode()))
        {
            long longVal = Convert.ToInt64(value);
            long longOpt = Convert.ToInt64(option);
            return (longVal & longOpt) == longOpt;
        }
        else
        {
            ulong longVal = Convert.ToUInt64(value);
            ulong longOpt = Convert.ToUInt64(option);
            return (longVal & longOpt) == longOpt;
        }
    }
}

Это работает отлично, вот так:

class Program
{
    static void Main(string[] args)
    {
        HtmlParserOptions opt1 = HtmlParserOptions.NotifyText | HtmlParserOptions.NotifyEmptyText;
        Console.WriteLine("Text: {0}", opt1.IsOptionSet(HtmlParserOptions.NotifyText));
        Console.WriteLine("OpeningTags: {0}", opt1.IsOptionSet(HtmlParserOptions.NotifyOpeningTags));

        Console.ReadKey();
    } 
}

Приведенные выше отпечатки:

Text: True
OpeningTags: False

Недостатком этого, однако, является то, что это не защищает вас от передачи двух разных типов перечислений в подпрограмму.Вы должны использовать его разумно.

Другие советы

Ну, вроде того.

Вы не можете добавить ограничение, чтобы убедиться, что аргумент type является перечислением "flags", и в обычном C # вы не можете добавить ограничение, чтобы убедиться, что это перечисление в первую очередь...но, немного поднапрягшись, вы можете заставить последнее сработать.Это допустимое ограничение в IL, но не в C #.Затем вам нужно будет немного поработать, чтобы заставить часть "и" работать в общем виде.

У меня есть проект под названием Непринужденная Мелодия который имеет несколько полезных методов расширения для перечислений, с помощью некоторой IL-перезаписи.В этом случае вы бы использовали:

if (options.HasAny(optionToTest))

или

if (options.HasAll(optionToTest))

в зависимости от того, как вы хотели бы справиться с ситуацией, когда optionToTest на самом деле это несколько объединенных флагов.

В качестве альтернативы, дождитесь .NET 4.0 - the изменения в BCL включать в себя Enum.HasFlag, который, я думаю, сделает то, что вы хотите.

public static bool IsOptionSet<T>(this T flags, T option) where T : struct
{
    if(! flags is int) throw new ArgumentException("Flags must be int");

    int opt = (int)(object)option;
    int fl = (int)(object)flags;
    return (fl & opt) == opt;
}

РЕДАКТИРОВАТЬ: как было отмечено в комментариях, это не будет работать, если enum - это что-то отличное от int (которое по умолчанию для enums). Вероятно, это должно быть названо как-то иначе, чтобы указать на это, но это, вероятно, «достаточно» для большинства случаев, если вам не нужен набор флагов с более чем 31 значением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top