C#でIntをジェネリック列挙型にキャストする


84

C#のCast int to enumに似ていますが、私の列挙型はGenericTypeパラメーターです。これを処理するための最良の方法は何ですか?

例:

private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
    return (T)i;
}

コンパイラエラーを生成します Cannot convert type 'int' to 'T'

完全なコードは次のとおりです。ここで、valueにはintまたはnullを含めることができます。

private int? TryParseInt(string value)
{
    var i = 0;
    if (!int.TryParse(value, out i))
    {
        return null;
    }
    return i;
}

private T? TryParseEnum<T>(string value) where T : struct, IConvertible
{
    var i = TryParseInt(value);
    if (!i.HasValue)
    {
        return null;
    }

    return (T)i.Value;
}

stackoverflow.com/questions/2745320/…-役立つかもしれませんか?
晴れ

stackoverflow.com/questions/1331739/…の最後の答えは、あなたが望むものに近いです。それでもまだ賢くはありません。私はこれにリフレクションを使用する傾向があります。コードをより強力にすることができます。私の意見では、Structはジェネリックをいじる価値のあるものにするほど制限的ではありません。
トニーホプキンソン2012

回答:


120

私が見つけた最も簡単な方法は、にキャストを追加してコンパイラの手を強制することobjectです。

return (T)(object)i.Value;

12
ボクシングが気に入らない場合:c-sharp-non-boxing-conversion-of-generic-enum-to-int
nawfal 2013年

5
リンクするSoの質問のように逆ではなく、列挙型をintにキャストしています。また、その質問には解決策がありません。
MatteoSp 2015

また、列挙値を使用して静的配列を割り当て、インデックスを渡して正しい列挙を取得することもできます。これにより、あらゆる種類のキャストを行う必要がなくなります。例(のみライン11,14、および34は、この概念に関連している):pastebin.com/iPEzttM4
Krythic


16

これは、ランタイムが静的ジェネリッククラスの複数のインスタンスを作成するという事実を悪用する非常に高速なソリューションです。あなたの内なる最適化の悪魔を解き放ちます!

これは、一般的な方法でストリームから列挙型を読み取るときに非常に役立ちます。列挙型の基になる型もキャッシュする外部クラスとBitConverterを組み合わせて、すばらしいものを解き放ちます。

void Main() 
{
    Console.WriteLine("Cast (reference): {0}", (TestEnum)5);
    Console.WriteLine("EnumConverter: {0}", EnumConverter<TestEnum>.Convert(5));
    Console.WriteLine("Enum.ToObject: {0}", Enum.ToObject(typeof(TestEnum), 5));

    int iterations = 1000 * 1000 * 100;
    Measure(iterations, "Cast (reference)", () => { var t = (TestEnum)5; });
    Measure(iterations, "EnumConverter", () => EnumConverter<TestEnum>.Convert(5));
    Measure(iterations, "Enum.ToObject", () => Enum.ToObject(typeof(TestEnum), 5));
}

static class EnumConverter<TEnum> where TEnum : struct, IConvertible
{
    public static readonly Func<long, TEnum> Convert = GenerateConverter();

    static Func<long, TEnum> GenerateConverter()
    {
        var parameter = Expression.Parameter(typeof(long));
        var dynamicMethod = Expression.Lambda<Func<long, TEnum>>(
            Expression.Convert(parameter, typeof(TEnum)),
            parameter);
        return dynamicMethod.Compile();
    }
}

enum TestEnum 
{
    Value = 5
}

static void Measure(int repetitions, string what, Action action)
{
    action();

    var total = Stopwatch.StartNew();
    for (int i = 0; i < repetitions; i++)
    {
        action();
    }
    Console.WriteLine("{0}: {1}", what, total.Elapsed);
}

最適化を有効にしたCorei7-3740QMでの結果:

Cast (reference): Value
EnumConverter: Value
Enum.ToObject: Value
Cast (reference): 00:00:00.3175615
EnumConverter: 00:00:00.4335949
Enum.ToObject: 00:00:14.3396366

2
これは本当にいいです、ありがとう。Expression.ConvertCheckedただし、代わりに使用して、列挙型の範囲の数値オーバーフローが。になるようにすることもできますOverflowException
ドリュー

あなたのマイレージは変わるかもしれません、私はtry.dot.net(blazor)でコードを実行しました、そしてそこでEnumConverter <T>は他のものよりはるかに遅いです。最初にオブジェクトにキャストするのは、直接キャストよりも約6倍遅くなりましたが、それでも他のオプションよりもはるかに優れていました。
ハーマン



0
public static class Extensions
    {
        public static T ToEnum<T>(this int param)
        {
            var info = typeof(T);
            if (info.IsEnum)
            {
                T result = (T)Enum.Parse(typeof(T), param.ToString(), true);
                return result;
            }

            return default(T);
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.