C#, Перечисление Флагов, Родовая функция для поиска флага

Я нашел следующий модуль python-simplexml , который в попытках автора получить что-то похожее на SimpleXML из PHP действительно является small wrapper around ElementTree. Это менее 100 строк, но, кажется, делает то, что было запрошено:

>>> import SimpleXml
>>> x = SimpleXml.parse(urllib.urlopen('http://www.google.com/ig/api?weather=94043'))
>>> print x.weather.current_conditions.temp_f['data']
58

13
задан akjoshi 19 June 2012 в 05:29
поделиться

9 ответов

Нет, вы не можете сделать это с помощью универсальных шаблонов C #. Однако вы могли бы сделать:

public static bool IsEnumFlagPresent<T>(T value, T lookingForFlag) 
    where T : struct
{
    int intValue = (int) (object) value;
    int intLookingForFlag = (int) (object) lookingForFlag;
    return ((intValue & intLookingForFlag) == intLookingForFlag);
}

Это будет работать только для перечислений, у которых есть базовый тип int , и это несколько неэффективно, потому что оно упаковывает значение ... но должно

Вы можете добавить проверку типа выполнения, что T действительно является типом перечисления (например, typeof (T) .BaseType == typeof (Enum) )

Вот полная программа, демонстрирующая он работает:

using System;

[Flags]
enum Foo
{
    A = 1,
    B = 2,
    C = 4,
    D = 8
}

class Test
{
    public static Boolean IsEnumFlagPresent<T>(T value, T lookingForFlag) 
        where T : struct
    {
        int intValue = (int) (object) value;
        int intLookingForFlag = (int) (object) lookingForFlag;
        return ((intValue & intLookingForFlag) == intLookingForFlag);
    }

    static void Main()
    {
        Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.A));
        Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.B));
        Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.C));
        Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.D));
    }
}
21
ответ дан 1 December 2019 в 17:18
поделиться

Вы хотите заменить одну строку кода функцией, которая завершает одну строку кода? Я бы сказал просто использовать одну строчку кода ...

22
ответ дан 1 December 2019 в 17:18
поделиться

Почему бы не написать для этого метод расширения? Я сделал это в другом посте

public static class EnumerationExtensions {

    public static bool Has<T>(this System.Enum type, T value) {
        try {
            return (((int)(object)type & (int)(object)value) == (int)(object)value);
        } 
        catch {
            return false;
        }
    }
    //... etc...

}

//Then use it like this
bool hasValue = permissions.Has(PermissionTypes.Delete);

Здесь можно было бы немного уточнить (поскольку предполагается, что все может быть преобразовано как int), но это может помочь вам начать ...

2
ответ дан 1 December 2019 в 17:18
поделиться

Вы можете сделать это без дженериков:

static bool ContainsFlags(Enum value, Enum flag)
{
    if (Enum.GetUnderlyingType(value.GetType()) == typeof(ulong))
        return (Convert.ToUInt64(value) & Convert.ToUInt64(flag)) == Convert.ToUInt64(flag);
    else
        return (Convert.ToInt64(value) & Convert.ToInt64(flag)) == Convert.ToInt64(flag);
}

В этом случае я конвертирую в Int64, который должен обрабатывать в каждом случае, кроме улонга, поэтому дополнительная проверка ...

2
ответ дан 1 December 2019 в 17:18
поделиться

Worth pointing out that simply providing some static overloads for all the integral types will work so long as you know you are working with a specific enum. They won't work if the consuming code is likewise operating on where t : struct

If you need to deal with arbitrary (struct) T

You cannot currently do a fast conversion of a generically typed struct into some alternate bitwise form (i.e. roughly speaking a reinterpret_cast) without using C++/CLI

generic <typename T>
where T : value class
public ref struct Reinterpret
{
    private:
    const static int size = sizeof(T);

    public:    
    static int AsInt(T t)
    {
        return *((Int32*) (void*) (&t));
    }
}

This will then let you write:

static void IsSet<T>(T value, T flags) where T : struct
{
    if (!typeof(T).IsEnum)
        throw new InvalidOperationException(typeof(T).Name +" is not an enum!");
    Type t = Enum.GetUnderlyingType(typeof(T));
    if (t == typeof(int))
    {
         return (Reinterpret.AsInt(value) & Reinterpret.AsInt(flags)) != 0
    }
    else if (t == typeof(byte))
    {
         return (Reinterpret.AsByte(value) & Reinterpret.AsByte(flags)) != 0
    }
    // you get the idea...        
}

You cannot constrain to enums. But the mathematical validity of these methods do not change if they are used with non enum types so you could allow them if you can determine that they are convertible to a struct of the relevant size.

1
ответ дан 1 December 2019 в 17:18
поделиться

Что ж, я не верю, что есть способ сделать это, поскольку нет ограничений, которые применяются к поразрядным операторам.

Однако ... вы можете просто преобразовать enum в int и сделать это.

public static Boolean IsEnumFlagPresent(int value,int lookingForFlag) 
{
    return ((value & lookingForFlag) == lookingForFlag);
}

Это работает, но может кого-то запутать.

0
ответ дан 1 December 2019 в 17:18
поделиться

Я уже использовал это раньше:

public static bool In<T>(this T me, T values)
    where T : struct, IConvertible
{
    return (me.ToInt64(null) & values.ToInt64(null)) > 0;
}

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

AttributeTargets a = AttributeTargets.Class;
if (a.In(AttributeTargets.Class | AttributeTargets.Module))
{
   // ...
}
6
ответ дан 1 December 2019 в 17:18
поделиться

Я недавно прочитал, что эта функция будет частью .NET 4.0. В частности, это реализовано в функции Enum.HasFlag () .

12
ответ дан 1 December 2019 в 17:18
поделиться

Вопрос давно закончился, но все же вот один для справки:

    public static bool HasFlag<TEnum>(this TEnum enumeratedType, TEnum value)
        where TEnum : struct, IComparable, IFormattable, IConvertible

    {
        if (!(enumeratedType is Enum))
        {
            throw new InvalidOperationException("Struct is not an Enum.");
        }

        if (typeof(TEnum).GetCustomAttributes(
            typeof(FlagsAttribute), false).Length == 0)
        {
            throw new InvalidOperationException("Enum must use [Flags].");
        }

        long enumValue = enumeratedType.ToInt64(CultureInfo.InvariantCulture);
        long flagValue = value.ToInt64(CultureInfo.InvariantCulture);

        if ((enumValue & flagValue) == flagValue)
        {
            return true;
        }

        return false;
    }
0
ответ дан 1 December 2019 в 17:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: