가능한 값에 대해 주어진 값 (문자열로 전달됨)의 유효성을 검사 할 수있는 함수를 작성하고 싶습니다 enum
. 일치하는 경우 열거 형 인스턴스를 반환해야합니다. 그렇지 않으면 기본값을 반환해야합니다.
함수는 내부적으로 try
/를 사용하지 않을 수 있습니다 . 이는 유효하지 않은 인수가 주어지면 예외를 발생시키는 catch
using을 제외합니다 Enum.Parse
.
이것을 TryParse
구현하기 위해 함수 라인을 따라 무언가를 사용하고 싶습니다 .
public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
object enumValue;
if (!TryParse (typeof (TEnum), strEnumValue, out enumValue))
{
return defaultValue;
}
return (TEnum) enumValue;
}
답변
다른 사람들이 말했듯이 자신 만의 TryParse
. Simon Mourier는 모든 것을 처리하는 완전한 구현을 제공합니다.
비트 필드 열거 형 (즉 플래그)을 사용하는 경우 "MyEnum.Val1|MyEnum.Val2"
두 열거 형 값의 조합 인 문자열도 처리해야 합니다. Enum.IsDefined
이 문자열로 호출 Enum.Parse
하면 올바르게 처리 하더라도 false를 반환 합니다.
최신 정보
주석에서 Lisa와 Christian이 언급했듯이 Enum.TryParse
이제 .NET4 이상에서 C #을 사용할 수 있습니다.
답변
Enum.IsDefined는 작업을 완료합니다. TryParse만큼 효율적이지 않을 수 있지만 예외 처리없이 작동합니다.
public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
return defaultValue;
return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}
주목할만한 점 TryParse
은 .NET 4.0에 메서드가 추가되었습니다.
답변
다음은 EnumTryParse
. 다른 일반적인 구현과 달리 Flags
속성으로 표시된 열거 형도 지원 합니다.
/// <summary>
/// Converts the string representation of an enum to its Enum equivalent value. A return value indicates whether the operation succeeded.
/// This method does not rely on Enum.Parse and therefore will never raise any first or second chance exception.
/// </summary>
/// <param name="type">The enum target type. May not be null.</param>
/// <param name="input">The input text. May be null.</param>
/// <param name="value">When this method returns, contains Enum equivalent value to the enum contained in input, if the conversion succeeded.</param>
/// <returns>
/// true if s was converted successfully; otherwise, false.
/// </returns>
public static bool EnumTryParse(Type type, string input, out object value)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsEnum)
throw new ArgumentException(null, "type");
if (input == null)
{
value = Activator.CreateInstance(type);
return false;
}
input = input.Trim();
if (input.Length == 0)
{
value = Activator.CreateInstance(type);
return false;
}
string[] names = Enum.GetNames(type);
if (names.Length == 0)
{
value = Activator.CreateInstance(type);
return false;
}
Type underlyingType = Enum.GetUnderlyingType(type);
Array values = Enum.GetValues(type);
// some enums like System.CodeDom.MemberAttributes *are* flags but are not declared with Flags...
if ((!type.IsDefined(typeof(FlagsAttribute), true)) && (input.IndexOfAny(_enumSeperators) < 0))
return EnumToObject(type, underlyingType, names, values, input, out value);
// multi value enum
string[] tokens = input.Split(_enumSeperators, StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length == 0)
{
value = Activator.CreateInstance(type);
return false;
}
ulong ul = 0;
foreach (string tok in tokens)
{
string token = tok.Trim(); // NOTE: we don't consider empty tokens as errors
if (token.Length == 0)
continue;
object tokenValue;
if (!EnumToObject(type, underlyingType, names, values, token, out tokenValue))
{
value = Activator.CreateInstance(type);
return false;
}
ulong tokenUl;
switch (Convert.GetTypeCode(tokenValue))
{
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.SByte:
tokenUl = (ulong)Convert.ToInt64(tokenValue, CultureInfo.InvariantCulture);
break;
//case TypeCode.Byte:
//case TypeCode.UInt16:
//case TypeCode.UInt32:
//case TypeCode.UInt64:
default:
tokenUl = Convert.ToUInt64(tokenValue, CultureInfo.InvariantCulture);
break;
}
ul |= tokenUl;
}
value = Enum.ToObject(type, ul);
return true;
}
private static char[] _enumSeperators = new char[] { ',', ';', '+', '|', ' ' };
private static object EnumToObject(Type underlyingType, string input)
{
if (underlyingType == typeof(int))
{
int s;
if (int.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(uint))
{
uint s;
if (uint.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(ulong))
{
ulong s;
if (ulong.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(long))
{
long s;
if (long.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(short))
{
short s;
if (short.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(ushort))
{
ushort s;
if (ushort.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(byte))
{
byte s;
if (byte.TryParse(input, out s))
return s;
}
if (underlyingType == typeof(sbyte))
{
sbyte s;
if (sbyte.TryParse(input, out s))
return s;
}
return null;
}
private static bool EnumToObject(Type type, Type underlyingType, string[] names, Array values, string input, out object value)
{
for (int i = 0; i < names.Length; i++)
{
if (string.Compare(names[i], input, StringComparison.OrdinalIgnoreCase) == 0)
{
value = values.GetValue(i);
return true;
}
}
if ((char.IsDigit(input[0]) || (input[0] == '-')) || (input[0] == '+'))
{
object obj = EnumToObject(underlyingType, input);
if (obj == null)
{
value = Activator.CreateInstance(type);
return false;
}
value = obj;
return true;
}
value = Activator.CreateInstance(type);
return false;
}
답변
결국 이것을 구현해야합니다 Enum.GetNames
.
public bool TryParseEnum<T>(string str, bool caseSensitive, out T value) where T : struct {
// Can't make this a type constraint...
if (!typeof(T).IsEnum) {
throw new ArgumentException("Type parameter must be an enum");
}
var names = Enum.GetNames(typeof(T));
value = (Enum.GetValues(typeof(T)) as T[])[0]; // For want of a better default
foreach (var name in names) {
if (String.Equals(name, str, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) {
value = (T)Enum.Parse(typeof(T), name);
return true;
}
}
return false;
}
추가 참고 사항 :
Enum.TryParse
.NET 4에 포함되어 있습니다 . 여기를 참조하십시오. http://msdn.microsoft.com/library/dd991876(VS.100).aspx- 또 다른 접근 방식은
Enum.Parse
실패 할 때 throw되는 예외를 포착하여 직접 래핑하는 것 입니다. 일치하는 항목이 발견되면 더 빠를 수 있지만 그렇지 않은 경우 속도가 느려질 수 있습니다. 처리중인 데이터에 따라 이것은 순 개선 일 수도 있고 아닐 수도 있습니다.
편집 : 필요한 정보를 캐시하는 더 나은 구현을 보았습니다. http://damieng.com/blog/2010/10/17/enums-better-syntax-improved-performance-and-tryparse-in-net- 3-5
답변
.NET 4.5 기반
아래 샘플 코드
using System;
enum Importance
{
None,
Low,
Medium,
Critical
}
class Program
{
static void Main()
{
// The input value.
string value = "Medium";
// An unitialized variable.
Importance importance;
// Call Enum.TryParse method.
if (Enum.TryParse(value, out importance))
{
// We now have an enum type.
Console.WriteLine(importance == Importance.Medium);
}
}
}
답변
UnconstrainedMelody 에서 사용할 수있는 최적화 된 구현이 있습니다 . 실제로는 이름 목록을 캐싱하는 것이지만 멋지고 강력하게 형식화되고 일반적으로 제한되는 방식으로 수행됩니다. 🙂
답변
enum EnumStatus
{
NAO_INFORMADO = 0,
ENCONTRADO = 1,
BLOQUEADA_PELO_ENTREGADOR = 2,
DISPOSITIVO_DESABILITADO = 3,
ERRO_INTERNO = 4,
AGARDANDO = 5
}
…
if (Enum.TryParse<EnumStatus>(item.status, out status)) {
}