16

フラグが存在するかどうかを確認するために、Flags スタイルの列挙型で使用できる汎用関数が 1 つ必要です。

これはコンパイルされませんが、誰かが提案を持っていれば、私はそれを感謝します.

public static Boolean IsEnumFlagPresent<T>(T value,T lookingForFlag) 
       where T:enum
{
    Boolean result = ((value & lookingForFlag) == lookingForFlag);
    return result ;            
}
4

11 に答える 11

26

いいえ、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));
    }
}
于 2009-06-12T16:26:02.703 に答える
23

1 行のコードを、1 行のコードをラップする関数に置き換えようとしていますか? 1行のコードを使用するだけだと思います...

于 2009-06-12T16:26:08.057 に答える
15

なんというか、最近、この機能が .NET 4.0 の一部になるという記事を読みました。具体的には、Enum.HasFlag()関数に実装されています。

于 2009-10-29T00:51:16.360 に答える
6

私は以前にこれを使用しました:

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))
{
   // ...
}
于 2009-06-12T16:47:23.200 に答える
2

このための拡張メソッドを書いてみませんか?私は別の投稿でこれをしました

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としてキャストできると想定しているため)、開始することはできます...

于 2009-06-12T16:47:22.637 に答える
1

質問は長くなりましたが、参考までに次の 1 つを示します。

    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;
    }
于 2009-11-26T18:16:40.140 に答える
1

特定の列挙型を使用していることがわかっている限り、すべての整数型にいくつかの静的オーバーロードを提供するだけで機能することを指摘する価値があります。消費するコードが同様に動作している場合、それらは機能しませんwhere t : struct

任意の (構造体) T を扱う必要がある場合

現在、C++/CLI を使用せずに、汎用的に型指定された構造体を別のビット単位の形式 (つまり、大まかに言うと reinterpret_cast) に高速に変換することはできません。

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));
    }
}

これにより、次のように記述できます。

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...        
}

列挙型に制限することはできません。ただし、これらのメソッドが非列挙型で使用されている場合、これらのメソッドの数学的有効性は変わらないため、関連するサイズの構造体に変換できると判断できる場合は許可できます。

于 2009-06-12T16:40:29.223 に答える
0

ビット単位の演算子に適用される制約がないため、これを行う方法があるとは思いません。

ただし...列挙型をintにキャストして実行するだけです。

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

これは機能しますが、誰かを混乱させる可能性があります。

于 2009-06-12T16:39:59.800 に答える
0

以下は、4 つの異なる方法をベンチマークするコードです。結果は、コメント「BENCHMARK: .. nSec」のコードに表示されます。

"((enum & flag) != 0)' は HasFlag() 関数よりも 10 倍高速です。タイトなループに陥っている場合は、それを受け入れるのが最善だと思います。

    public static int jumpCtr=0;
    public static int ctr=0;
    public static TestFlags gTestFlags = TestFlags.C;
    [Flags] public enum TestFlags { A=1<<1, B=1<<2, C=1<<3 }
    public static void Jump()  { jumpCtr++; gTestFlags = (gTestFlags == TestFlags.B) ? TestFlags.C : TestFlags.B;  }

    // IsEnumFlagPresent() https://stackoverflow.com/questions/987607/c-flags-enum-generic-function-to-look-for-a-flag
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasFlag_Faster<T>(T value, T lookingForFlag) 
        where T : struct
    {
        int intValue                = (int) (object) value;
        int intLookingForFlag       = (int) (object) lookingForFlag;
        return ((intValue & intLookingForFlag) != 0);
    }

    // IsEnumFlagPresent() https://stackoverflow.com/questions/987607/c-flags-enum-generic-function-to-look-for-a-flag
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasFlag_Faster_Integer(int intValue, int intLookingForFlag) 
    {
        return ((intValue & intLookingForFlag) != 0);
    }

    public static void Benchmark_HasFlag( )  
    {
        if ( ! hwDvr._weAreOnGswCpu) { return; }

        DateTime timer = DateTime.Now; 
        string a, b, c, d, e;
        double base_nSecPerLoop, b_nSecPerLoop, c_nSecPerLoop, d_nSecPerLoop, e_nSecPerLoop;
        int numOfLoops = (int) 1.0e6;

        //  ------------------------------------------------------
        for (int i=0; i<numOfLoops;i++) {
            Jump();
        }
        a = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out base_nSecPerLoop);

        //  ------------------------------------------------------
        //  BENCHMARK: 50 nSec

        for (int i=0; i<numOfLoops;i++) {
            if (gTestFlags.HasFlag((TestFlags) TestFlags.C)) {   
                ctr++;
            }
            Jump();
        }
        b = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out b_nSecPerLoop );

        double b_diff = b_nSecPerLoop - base_nSecPerLoop;

        //  ------------------------------------------------------
        //  BENCHMARK: 3 nSec

        for (int i=0; i<numOfLoops;i++) {
            if ((gTestFlags & TestFlags.C) != 0) {   
                ctr++;
            }
            Jump();
        }
        c = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out c_nSecPerLoop );

        double c_diff = c_nSecPerLoop - base_nSecPerLoop;

        //  ------------------------------------------------------
        //  BENCHMARK: 64 nSec

        for (int i=0; i<numOfLoops;i++) {
            if (HasFlag_Faster<TestFlags>(value:gTestFlags, lookingForFlag: TestFlags.C)) {   
                ctr++;
            }
            Jump();
        }
        d = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out d_nSecPerLoop );

        double d_diff = d_nSecPerLoop - base_nSecPerLoop;

        //  ------------------------------------------------------
        //  BENCHMARK: 14 nSec

        for (int i=0; i<numOfLoops;i++) {
            if (HasFlag_Faster_Integer((int)gTestFlags, (int)TestFlags.C)) {   
                ctr++;
            }
            Jump();
        }
        e = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out e_nSecPerLoop );

        double e_diff = e_nSecPerLoop - base_nSecPerLoop;

        int brkPt=0;
    }
于 2018-06-19T15:05:52.393 に答える