Можно ли создать общий метод побитового перечисления IsOptionSet ()? - PullRequest
4 голосов
/ 23 октября 2009

Приведенный ниже код упрощает передачу набора 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? *

Ответы [ 3 ]

7 голосов
/ 23 октября 2009

Edit:

Самый простой и приятный вариант - перейти на VS2010 Beta2 и использовать Enum.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

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

3 голосов
/ 23 октября 2009

Ну, вроде как.

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

У меня есть проект под названием Unconstrained Melody , в котором есть несколько полезных методов расширения для перечислений посредством некоторой перезаписи IL. В этом случае вы бы использовали:

if (options.HasAny(optionToTest))

или

if (options.HasAll(optionToTest))

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

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

3 голосов
/ 23 октября 2009
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 значением.

...