System.Enum에서 기본 정수로 변환하는 방법은 무엇입니까?


93

캐스팅하지 않고 바람직하게는 문자열을 구문 분석하지 않고 System.Enum 파생 형식을 해당 정수 값으로 변환하는 일반 메서드를 만들고 싶습니다.

예를 들어, 내가 원하는 것은 다음과 같습니다.

// Trivial example, not actually what I'm doing.
class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        (int)anEnum;
    }
}

그러나 이것은 작동하지 않는 것 같습니다. Resharper는 'System.Enum'형식의 식을 'int'형식으로 캐스팅 할 수 없다고보고합니다.

이제이 솔루션을 생각해 냈지만 더 효율적인 방법을 원합니다.

class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        return int.Parse(anEnum.ToString("d"));
    }
}

어떤 제안?


1
Resharper가 아니라 불평하는 컴파일러라고 생각합니다.
Kugel 2012-08-28

1
반드시 그런 것은 아닙니다. System.Enum에 대한 확장 메서드가 있고 가끔 Resharper가 불평하기로 결정했습니다. 코드를 컴파일하고 실행하면 잘 작동합니다. 그런 다음 VS를 종료하고 Resharper 캐시를 날려 버리고 다시 실행하면 재검색이 완료되면 모든 것이 정상입니다. 나를 위해 그것은 일종의 캐시 snafu입니다. 그에게도 동일 할 수 있습니다.
미르

@Mir 저는 ReSharper도 이것에 대해 "불만"했습니다. 나에게도 같은 수정. 왜 이러한 유형이 뒤섞 이는지는 확실하지 않지만 확실히 컴파일러는 아닙니다.
akousmata

답변:


134

캐스팅하고 싶지 않다면

Convert.ToInt32()

트릭을 할 수 있습니다.

직접 캐스트 (를 통해 (int)enumValue)는 불가능합니다. 열거 다른 기본 유형을 가질 수 있기 때문에이 또한 "위험"이 될 것이라고 주 ( int, long, byte...).

보다 공식적으로 : (둘 다 s 임에도 불구하고) System.Enum직접 상속 관계가 없으므로 유형 시스템 내에서 명시 적 캐스트가 정확할 수 없습니다.Int32ValueType


2
Converter.ToInteger(MyEnum.MyEnumConstant);여기에 오류가 없습니다. 그 부분을 편집하십시오.
nawfal

감사합니다, @nawfal, 당신 말이 맞습니다. 나는 (... :) 뭔가 새로운 것을 배웠) 응답을 편집
MartinStettner

에서 형 다르다 기본 경우 작동하지 않습니다int
알렉스 쥬 코브 스키

@YaroslavSivakov 그것은 예를 들어 long열거 형에 대해 작동하지 않습니다 .
Alex Zhukovskiy

System.Enum클래스이므로 참조 유형입니다. 값은 아마도 박스형입니다.
Teejay

42

객체로 캐스팅 한 다음 int로 캐스팅하여 작동하도록했습니다.

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return (int)((object)enumValue);
    }
}

이것은 추악하고 아마도 최선의 방법은 아닙니다. 나는 더 나은 것을 생각 해낼 수 있는지보기 위해 그것을 계속 엉망으로 만들 것이다 ....

편집 : Convert.ToInt32 (enumValue)도 작동한다는 것을 게시하려고했으며 MartinStettner가 나를 이겼 음을 알았습니다.

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

테스트:

int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday

편집 2 : 의견에서 누군가가 이것이 C # 3.0에서만 작동한다고 말했습니다. 방금 VS2005에서 이것을 다음과 같이 테스트했으며 작동했습니다.

public static class Helpers
{
    public static int ToInt(Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

    static void Main(string[] args)
    {
        Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
    }

+1을했지만이 솔루션은 C # 3.0 이상에서만 작동합니다.
Vadim

나는 이것이 컴파일러를 만족한다고 생각합니다. 런타임에 이것을 테스트 했습니까? 이 함수에 값을 전달할 수 없습니다 ...
MartinStettner

확장 방법이기 때문에? 아니면 이전 버전의 C #에서 열거 형과 다른 점이 있습니까?
BFree

게시물 끝에 테스트를 추가했습니다. 나는 그것을 시도했고 그것은 나를 위해 일했습니다.
BFree

@BFree : 확장 메서드에서만 작동하는 것 같습니다. "이전 스타일"함수 (C # 2.0)로 시도했지만 실제로 값을 전달하는 구문을 찾지 못했습니다 (이전 의견에 대한 내용입니다)
MartinStettner

14

당신이 변환해야하는 경우 어떤 (모든 열거 형에 의해 뒷받침되지는 기본 유형 열거 int) 당신은 사용할 수 있습니다 :

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));

5
이것이 유일한 방탄 답변입니다.
Rudey

이것이 권투 개봉의 원인입니까?
b.ben

@ b.ben 예. 첫 번째 인수를 Convert.ChangeType허용 object하고를 반환합니다 object.
Drew Noakes

네, 실제로 @Rudey에 동의합니다. 어쨌든 성능 테스트를해야합니다. BFree의 솔루션이 가장 빠릅니다. 약 8 배 더 빠릅니다. 어쨌든 우리는 여전히 진드기에 대해 이야기하고 있습니다.
20

10

도우미 메서드를 사용하여 바퀴를 재발 명해야하는 이유는 무엇입니까? enum값을 기본 유형 으로 캐스팅하는 것은 완벽하게 합법적 입니다.

타이핑이 적고 사용하기가 더 읽기 쉽습니다.

int x = (int)DayOfWeek.Tuesday;

... 같은 것보다 ...

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();

6
모든 열거 형 값을 변환하고 싶습니다. 즉, 일반적인 방식으로 일부 코드에서 처리되는 열거 형 필드가있는 다양한 클래스가 있습니다. 이것이 int 로의 단순 캐스트가 적절하지 않은 이유입니다.
orj

@orj, 무슨 말인지 잘 모르겠습니다. 필요한 사용법을 보여주는 예를 들어 줄 수 있습니까?
LukeH

2
제네릭 메서드의 경우와 같이 열거 형을 직접 캐스팅 할 수없는 경우도 있습니다. 제네릭 메서드는 열거 형으로 제한 할 수 없기 때문에 int로 캐스팅 할 수없는 struct와 같은 것으로 제한해야합니다. 이 경우 Convert.ToInt32 (enum)을 사용하여 수행 할 수 있습니다.
Daniel T.

확장 메서드 ToInteger ()가 ToString ()과 같은 형식을 따른다는 생각이 마음에 듭니다. int 값을 원할 때 int로 캐스팅하고 특히 코드가 나란히있을 때 문자열 값이 필요할 때 ToString ()을 사용하는 것이 읽기 쉽지 않다고 생각합니다.
Louise Eggleton

또한 확장 메서드를 사용하면 코드베이스에 일관성을 추가 할 수 있습니다. @nawfal이 지적했듯이 열거 형에서 int 값을 얻을 수있는 몇 가지 방법이 있기 때문에 확장 메서드를 만들고 사용을 적용한다는 것은 enum의 int 값을 얻을 때마다 동일한 메서드를 사용한다는 것을 의미합니다.
Louise Eggleton

4

여기 내 대답 에서 :

다음 e과 같이 주어 집니다.

Enum e = Question.Role;

그런 다음 작동합니다.

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

마지막 두 개는 아주 추합니다. 첫 번째는 더 읽기 쉬워야하지만 두 번째는 훨씬 빠릅니다. 또는 확장 방법이 두 세계 모두에서 최고 일 수 있습니다.

public static int GetIntValue(this Enum e)
{
    return e.GetValue<int>();
}

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    return (T)(object)e;
}

이제 다음을 호출 할 수 있습니다.

e.GetValue<int>(); //or
e.GetIntValue();

두 번째 것이 더 빠르다고 확신합니까? enum을 boxing하고 int로 다시 unbox 할 것이라고 가정합니다.
yoyo

1
@yoyo e변수에는 이미 실제 값 유형, 즉 enum의 박스형 인스턴스가 있습니다. 당신이 쓸 때 Enum e = Question.Role;이미 박스형입니다. 문제는 boxed System.Enum를 기본 int 유형 (unboxing)으로 다시 변환하는 것 입니다. 따라서 여기서 unboxing은 성능 문제 일뿐입니다. (int)(object)e직접 unbox 호출입니다. 예는 다른 접근 방식보다 빠릅니다. 이 참조
nawfal

설명해 주셔서 감사합니다. System.Enum의 인스턴스가 unboxed 값이라는 잘못된 인상을 받았습니다. 이것도 참조하십시오 -msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx
yoyo

@yoyo 흠 예. 링크의 관련 인용문 : 모든 열거 형 형식에서 System.Enum 형식까지.
nawfal

1

a에서로 캐스팅 System.Enum하면 int잘 작동합니다 ( MSDN 에도 있습니다 ). 아마도 Resharper 버그 일 것입니다.


1
어떤 버전의 런타임을 사용하고 있습니까?
JoshBerke

2
링크는 자체가 System.Enum아닌 의 하위 유형 캐스팅을 보여줍니다 System.Enum.
nawfal 2013

내가 가진 비슷한 문제는 Resharper 캐시 snafu였습니다. VS를 닫고 Resharper 캐시를 삭제하면 전체 재검색 후에도 오류가 사라졌습니다.
미르

1

Enum은 byte, sbyte, short, ushort, int, uint, long 및 ulong으로 제한되므로 몇 가지 가정을 할 수 있습니다.

사용 가능한 가장 큰 컨테이너를 사용하여 변환 중에 예외를 피할 수 있습니다. 불행히도, ulong은 음수로 폭발하고 long은 long.MaxValue와 ulong.MaxValue 사이의 숫자로 폭발하기 때문에 어떤 컨테이너를 사용할지는 명확하지 않습니다. 기본 유형에 따라 이러한 선택을 전환해야합니다.

물론 결과가 int 안에 맞지 않을 때 무엇을해야할지 결정해야합니다. 캐스팅은 괜찮다고 생각하지만 여전히 몇 가지 문제가 있습니다.

  1. int (long 및 ulong)보다 큰 필드 공간을 가진 유형을 기반으로하는 열거 형의 경우 일부 열거 형이 동일한 값으로 평가 될 수 있습니다.
  2. int.MaxValue보다 큰 숫자를 캐스팅하면 선택된 영역에있는 경우 예외가 발생합니다.

여기에 제 제안이 있습니다.이 기능을 어디에 노출 시킬지 결정하기 위해 독자에게 맡기겠습니다. 도우미 또는 확장으로.

public int ToInt(Enum e)
{
  unchecked
  {
    if (e.GetTypeCode() == TypeCode.UInt64)
      return (int)Convert.ToUInt64(e);
    else
      return (int)Convert.ToInt64(e);
  }
}

-1

Enum 유형 자체에 많은 정적 도우미 함수가 있다는 것을 잊지 마십시오. 원하는 것이 열거 형의 인스턴스를 해당 정수 유형으로 변환하는 것뿐이라면 캐스팅이 아마도 가장 효율적인 방법 일 것입니다.

ReSharper는 Enum이 특정 유형의 열거 형이 아니고 열거 형 자체가 Enum이 아닌 스칼라 값 유형에서 파생되기 때문에 불평하고 있다고 생각합니다. 일반적인 방식으로 적응 가능한 캐스팅이 필요한 경우 이것이 적합하다고 말할 수 있습니다 (열거 형 유형 자체도 제네릭에 포함됩니다.

public static EnumHelpers
{
    public static T Convert<T, E>(E enumValue)
    {
        return (T)enumValue;
    }
}

그러면 다음과 같이 사용할 수 있습니다.

public enum StopLight: int
{
    Red = 1,
    Yellow = 2,
    Green = 3
}

// ...

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);

내 머리 꼭대기에서 확실히 말할 수는 없지만 위의 코드는 C #의 유형 추론에 의해 지원 될 수도 있으므로 다음을 허용합니다.

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);

1
불행히도 귀하의 예에서 E는 모든 유형이 될 수 있습니다. Generics는 유형 매개 변수 제약 조건으로 Enum을 사용하는 것을 허용하지 않습니다. 나는 말할 수 없다 : 어디 T : Enum
Vadim

그래도 T : struct 어디에 사용할 수 있습니다. 그 확실히 당신이 원하는,하지만 어떤 참조 타입 잘라하는 것처럼 엄격한으로 (난 당신이 뭘하려고 무엇을 생각합니다.)
jrista

다음을 사용할 수 있습니다. if (! typeof (E) .IsEnum) throw new ArgumentException ( "E must be an enumerated type");
diadiora 2010

1
이것은 원격으로도 정확하지 않으며 정적 도우미도 유효하지 않습니다.
Nicholi

1
EnumHelpers.Convert<int, StopLight>(StopLight.Red);대신 누군가를 사용해야 하는 이유는 무엇 (int)StopLight.Read;입니까? 또한 질문은에 대해 이야기하고 System.Enum있습니다.
nawfal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.