Int를 C #의 Generic Enum으로 캐스팅


84

유사 캐스트 INT는 C #에서 열거 형 하지만 내 열거 형은 제네릭 형식 매개 변수입니다. 이를 처리 하는 가장 좋은 방법 은 무엇입니까 ?

예:

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/1331739/…의 마지막 답변 은 원하는 것에 더 가깝습니다. 그래도 여전히 영리하지 않습니다. 나는 이것을 위해 리플렉션을 사용하는 경향이 있으며 코드를 훨씬 더 강하게 만들 수 있습니다. Struct는 제 생각에 제네릭을 엉망으로 만들만큼 충분히 굴복하지 않습니다.
Tony Hopkinson 2012

답변:


120

내가 찾은 가장 간단한 방법은에 캐스트를 추가하여 컴파일러의 손을 강제하는 것 object입니다.

return (T)(object)i.Value;

12
당신은 권투 마음에 들지 않으면 : C-날카로운 비 - 복싱 - 변환 -의 - 일반 - 열거 - 투 - INT
nawfal

5
우리는 당신이 연결하는 So 질문 에서와는 반대로 enum을 int로 캐스팅하고 있습니다. 또한 그 질문에는 해결책이 없습니다.
MatteoSp

열거 형 값으로 정적 배열을 할당 한 다음 인덱스를 전달하여 올바른 열거 형을 검색 할 수도 있습니다. 이렇게하면 모든 종류의 캐스팅을 수행 할 필요가 없습니다. 예 (11,14 및 34
행만


16

다음은 런타임이 정적 제네릭 클래스의 여러 인스턴스를 생성한다는 사실을 남용하는 매우 빠른 솔루션입니다. 내면의 최적화 악마를 풀어보세요!

이것은 일반적인 방식으로 스트림에서 Enum을 읽을 때 정말 빛납니다. enum의 기본 유형 및 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);
}

최적화가 활성화 된 Core i7-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대신 사용하고 싶을 수 있으므로 enum 유형 범위의 숫자 오버플로가 OverflowException.
Drew Noakes

마일리지가 다를 수 있으며 try.dot.net (blazor)에서 코드를 실행했으며 EnumConverter <T>가 대안보다 훨씬 느립니다. 먼저 개체로 캐스팅하는 것은 직접 캐스팅보다 약 6 배 느리지 만 여전히 다른 옵션보다 훨씬 낫습니다.
Herman 19



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.