다음과 같은 열거 형이있는 경우 :
enum Beer
{
Bud = 10,
Stella = 20,
Unknown
}
int
이 값을 벗어난을 유형으로 캐스팅 할 때 왜 예외가 발생하지 Beer
않습니까?
예를 들어 다음 코드는 예외를 throw하지 않고 콘솔에 ’50’을 출력합니다.
int i = 50;
var b = (Beer) i;
Console.WriteLine(b.ToString());
나는 이것이 이상하다는 것을 알았다. 누구든지 명확히 할 수 있는가?
답변
에서 촬영 열거 구문 분석과 혼란
이것은 .NET을 만든 사람들의 결정이었습니다. 열거가 (다른 값 유형에 의해 백업됩니다 int
, short
,byte
실제로 그 값 유형에 대한 유효 값을 가질 수 있도록, 등)합니다.
나는 개인적으로 이것이 작동하는 방식을 좋아하지 않으므로 일련의 유틸리티 방법을 만들었습니다.
/// <summary>
/// Utility methods for enum values. This static type will fail to initialize
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
where T : struct, IConvertible // Try to get as much of a static check as we can.
{
// The .NET framework doesn't provide a compile-checked
// way to ensure that a type is an enum, so we have to check when the type
// is statically invoked.
static EnumUtil()
{
// Throw Exception on static initialization if the given type isn't an enum.
Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
}
/// <summary>
/// In the .NET Framework, objects can be cast to enum values which are not
/// defined for their type. This method provides a simple fail-fast check
/// that the enum value is defined, and creates a cast at the same time.
/// Cast the given value as the given enum type.
/// Throw an exception if the value is not defined for the given enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="enumValue"></param>
/// <exception cref="InvalidCastException">
/// If the given value is not a defined value of the enum type.
/// </exception>
/// <returns></returns>
public static T DefinedCast(object enumValue)
{
if (!System.Enum.IsDefined(typeof(T), enumValue))
throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
typeof (T).FullName);
return (T) enumValue;
}
/// <summary>
///
/// </summary>
/// <param name="enumValue"></param>
/// <returns></returns>
public static T Parse(string enumValue)
{
var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
//Require that the parsed value is defined
Require.That(parsedValue.IsDefined(),
() => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}",
enumValue, typeof(T).FullName)));
return parsedValue;
}
public static bool IsDefined(T enumValue)
{
return System.Enum.IsDefined(typeof (T), enumValue);
}
}
public static class EnumExtensions
{
public static bool IsDefined<T>(this T enumValue)
where T : struct, IConvertible
{
return EnumUtil<T>.IsDefined(enumValue);
}
}
이렇게 말할 수 있습니다.
if(!sEnum.IsDefined()) throw new Exception(...);
… 또는 :
EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.
편집하다
위에 제공된 설명 외에도 Enum의 .NET 버전은 Java에서 영감을받은 패턴보다 C에서 영감을받은 패턴을 따릅니다. 이렇게하면 이진 패턴을 사용하여 특정 “플래그”가 열거 형 값에서 활성 상태인지 여부를 확인할 수 있는 “비트 플래그”열거 형 을 가질 수 있습니다. 가능한 모든 플래그 조합 (예 : MondayAndTuesday
, MondayAndWednesdayAndThursday
) 을 정의해야한다면 매우 지루할 것입니다. 따라서 정의되지 않은 열거 형 값을 사용할 수있는 능력이 있으면 정말 편리 할 수 있습니다. 이러한 종류의 트릭을 활용하지 않는 enum 유형에 대한 빠른 실패 동작을 원할 때 약간의 추가 작업이 필요합니다.
답변
열거 형은 종종 플래그로 사용됩니다.
[Flags]
enum Permission
{
None = 0x00,
Read = 0x01,
Write = 0x02,
}
...
Permission p = Permission.Read | Permission.Write;
p의 값은 정수 3이며 열거 형의 값은 아니지만 유효한 값입니다.
나는 개인적으로 다른 해결책을 보았을 것입니다. 나는 “비트 배열”정수 유형 과 “고유 한 값의 세트”유형을 둘 다 “열거 형”으로 병합하는 것보다 두 가지 다른 언어 기능으로 만드는 기능을 갖고 싶었습니다. 하지만 이것이 원래 언어와 프레임 워크 디자이너가 생각 해낸 것입니다. 결과적으로 우리는 선언되지 않은 열거 형 값을 합법적 인 값으로 허용해야합니다.
답변
짧은 대답 : 언어 디자이너는 이러한 방식으로 언어를 디자인하기로 결정했습니다.
Section 6.2.2: Explicit enumeration conversions
C # 언어 사양 의 긴 대답은 다음 과 같습니다.
두 유형 간의 명시 적 열거 변환은 참여하는 열거 형 유형을 해당 열거 형 유형의 기본 유형으로 처리 한 다음 결과 유형간에 암시 적 또는 명시 적 숫자 변환을 수행하여 처리됩니다. 예를 들어, 기본 유형이 int 인 enum 유형 E가있는 경우 E에서 바이트로의 변환은 int에서 바이트로의 명시 적 숫자 변환 (§6.2.1)으로 처리되고 바이트에서 E 로의 변환은 다음과 같이 처리됩니다. byte에서 int 로의 암시 적 숫자 변환 (§6.1.2)
기본적으로 enum 은 변환 작업을 수행 할 때 기본 유형으로 처리됩니다. 기본적으로 enum 의 기본 유형은 Int32
입니다. 즉, 변환이 로의 변환과 똑같이 처리됩니다 Int32
. 이는 모든 유효한 int
값이 허용됨을 의미합니다 .
나는 이것이 주로 성능상의 이유로 수행되었다고 생각합니다. enum
간단한 정수 형식 을 만들고 정수 형식 변환을 허용하면 CLR이 모든 추가 검사를 수행 할 필요가 없습니다. 이는 enum
정수를 사용하는 것과 비교할 때 an을 사용하는 것이 실제로 성능 손실 이 없음을 의미하므로 사용 을 장려하는 데 도움이됩니다.