programing

C #에서 문자열을 열거 형으로 변환

nasanasas 2020. 9. 29. 07:53
반응형

C #에서 문자열을 열거 형으로 변환


C #에서 문자열을 열거 형 값으로 변환하는 가장 좋은 방법은 무엇입니까?

열거 형 값이 포함 된 HTML 선택 태그가 있습니다. 페이지가 게시 될 때 값 (문자열 형식)을 선택하여 열거 형 값으로 변환하고 싶습니다.

이상적인 세계에서는 다음과 같이 할 수 있습니다.

StatusEnum MyStatus = StatusEnum.Parse("Active");

그러나 그것은 유효한 코드가 아닙니다.


.NET Core 및 .NET> 4 에는 일반적인 구문 분석 방법이 있습니다 .

Enum.TryParse("Active", out StatusEnum myStatus);

여기에는 C # 7의 새로운 인라인 out변수 도 포함되어 있으므로 try-parse를 수행하고 명시 적 열거 형 형식으로 변환하고 myStatus변수를 초기화 + 채 웁니다 .

C # 7 및 최신 .NET에 액세스 할 수있는 경우 이것이 가장 좋은 방법입니다.

원래 답변

.NET에서는 다소 추합니다 (4 이상까지).

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

나는 이것을 다음과 같이 단순화하는 경향이 있습니다.

public static T ParseEnum<T>(string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

그런 다음 할 수 있습니다.

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

주석에서 제안 된 한 가지 옵션은 확장 기능을 추가하는 것입니다.

public static T ToEnum<T>(this string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

마지막으로 문자열을 구문 분석 할 수없는 경우 사용할 기본 열거 형을 가질 수 있습니다.

public static T ToEnum<T>(this string value, T defaultValue) 
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

이를 호출합니다.

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

그러나 string(네임 스페이스 제어없이) string열거 형을 보유하는지 여부 에 대한 모든 인스턴스에 표시되므로 이와 같은 확장 메서드를 추가하는 데주의해야 합니다 ( 1234.ToString().ToEnum(StatusEnum.None)유효하지만 의미가 없음). 전체 개발 팀이 이러한 확장 기능을 잘 이해하고 있지 않는 한 매우 특정한 상황에서만 적용되는 추가 메서드로 Microsoft의 핵심 클래스를 복잡하게 만드는 것을 피하는 것이 가장 좋습니다.


사용 Enum.TryParse<T>(String, T)(≥ .NET 4.0) :

StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);

C # 7.0의 매개 변수 유형 인라이닝을 사용 하면 더욱 단순화 할 수 있습니다 .

Enum.TryParse("Active", out StatusEnum myStatus);

의 성능은 Enum.Parse()리플렉션을 통해 구현되기 때문에 끔찍합니다. (에도 마찬가지이며 Enum.ToString반대 방향으로 진행됩니다.)

성능에 민감한 코드에서 문자열을 열거 형으로 변환해야하는 경우 가장 좋은 방법은 Dictionary<String,YourEnum>시작할 때을 만들고이를 사용하여 변환하는 것입니다.


당신은 Enum.Parse를 찾고 있습니다.

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");

이제 확장 메서드 를 사용할 수 있습니다 .

public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
    return (T) Enum.Parse(typeof (T), value, ignoreCase);
}

그리고 아래 코드로 호출 할 수 있습니다 (여기서는 FilterType열거 형 유형).

FilterType filterType = type.ToEnum<FilterType>();

object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

따라서 mood라는 이름의 열거 형이 있다면 다음과 같이 보일 것입니다.

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());

주의 :

enum Example
{
    One = 1,
    Two = 2,
    Three = 3
}

Enum.(Try)Parse() 쉼표로 구분 된 여러 인수를 허용하고 이진 'or'와 결합합니다| . 당신은 이것을 비활성화 할 수 없으며 제 생각에는 거의 원하지 않습니다.

var x = Enum.Parse("One,Two"); // x is now Three

Three정의되지 않은 경우에도 x여전히 int value를 얻습니다 3. 그것은 더 나쁜 것입니다 : Enum.Parse ()는 열거 형에 대해 정의되지 않은 값을 줄 수 있습니다!

나는이 행동을 유발하는 사용자의 결과를 기꺼이 또는 의도하지 않게 경험하고 싶지 않습니다.

또한 다른 사람들이 언급했듯이 성능은 큰 열거 형, 즉 가능한 값의 수가 선형 인 경우 이상적이지 않습니다.

다음을 제안합니다.

    public static bool TryParse<T>(string value, out T result)
        where T : struct
    {
        var cacheKey = "Enum_" + typeof(T).FullName;

        // [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
        // [Implementation off-topic.]
        var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);

        return enumDictionary.TryGetValue(value.Trim(), out result);
    }

    private static Dictionary<string, T> CreateEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
    }

Enum.Parse 는 당신의 친구입니다 :

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");

예외를 피하기 위해 기본값으로 수락 된 답변을 확장 할 수 있습니다.

public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
    try
    {
        T enumValue;
        if (!Enum.TryParse(value, true, out enumValue))
        {
            return defaultValue;
        }
        return enumValue;
    }
    catch (Exception)
    {
        return defaultValue;
    }
}

그런 다음 다음과 같이 부릅니다.

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);

기본값이 열거 형이 아닌 경우 Enum.TryParse는 실패하고 catch되는 예외를 throw합니다.

여러 곳에서 우리 코드에서이 함수를 수년간 사용한 후에는이 작업이 성능을 저하 시킨다는 정보를 추가하는 것이 좋습니다!


우리는 완벽하게 유효한 입력을 가정 할 수 없었으며 @Keith의 답변을 다음과 같이 변형했습니다.

public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    TEnum tmp; 
    if (!Enum.TryParse<TEnum>(value, true, out tmp))
    {
        tmp = new TEnum();
    }
    return tmp;
}

// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}

.NET 4.5에서 try / catch 및 TryParse () 메서드없이 문자열을 TEnum으로 구문 분석

/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
    enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
    if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
        return false;

    enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
    return true;
}

TryParse를 사용하는 매우 간단한 코드 :

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;

확장 방식 솔루션이 마음에 들어요 ..

namespace System
{
    public static class StringExtensions
    {

        public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
        {
            T result;

            var isEnum = Enum.TryParse(value, out result);

            output = isEnum ? result : default(T);

            return isEnum;
        }
    }
}

여기에 테스트를 통한 구현이 있습니다.

using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;

private enum Countries
    {
        NorthAmerica,
        Europe,
        Rusia,
        Brasil,
        China,
        Asia,
        Australia
    }

   [TestMethod]
        public void StringExtensions_On_TryParseAsEnum()
        {
            var countryName = "Rusia";

            Countries country;
            var isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsTrue(isCountry);
            AreEqual(Countries.Rusia, country);

            countryName = "Don't exist";

            isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsFalse(isCountry);
            AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
        }

public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

Importance imp = EnumUtil.ParseEnum<Importance>("Active");   //function call

==================== 전체 프로그램 ===================

using System;

class Program
{
    enum PetType
    {
    None,
    Cat = 1,
    Dog = 2
    }

    static void Main()
    {

    // Possible user input:
    string value = "Dog";

    // Try to convert the string to an enum:
    PetType pet = (PetType)Enum.Parse(typeof(PetType), value);

    // See if the conversion succeeded:
    if (pet == PetType.Dog)
    {
        Console.WriteLine("Equals dog.");
    }
    }
}
-------------
Output

Equals dog.

나는 클래스 (파싱 및 성능 향상을 가진 강력한 형식의 Enum 버전)을 사용했습니다. GitHub에서 찾았으며 .NET 3.5에서도 작동합니다. 사전을 버퍼링하기 때문에 약간의 메모리 오버 헤드가 있습니다.

StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");

블로그 게시물은 Enums – 더 나은 구문, 향상된 성능 및 NET 3.5의 TryParse입니다 .

코드 : https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs


성능을 위해 도움이 될 수 있습니다.

    private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
    public static T ToEnum<T>(this string value, T defaultValue)
    {
        var t = typeof(T);
        Dictionary<string, object> dic;
        if (!dicEnum.ContainsKey(t))
        {
            dic = new Dictionary<string, object>();
            dicEnum.Add(t, dic);
            foreach (var en in Enum.GetValues(t))
                dic.Add(en.ToString(), en);
        }
        else
            dic = dicEnum[t];
        if (!dic.ContainsKey(value))
            return defaultValue;
        else
            return (T)dic[value];
    }

I found that here the case with enum values that have EnumMember value was not considered. So here we go:

using System.Runtime.Serialization;

public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    TEnum result;
    var enumType = typeof(TEnum);
    foreach (var enumName in Enum.GetNames(enumType))
    {
        var fieldInfo = enumType.GetField(enumName);
        var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
        if (enumMemberAttribute?.Value == value)
        {
            return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
        }
    }

    return Enum.TryParse(value, true, out result) ? result : defaultValue;
}

And example of that enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}

You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

Try this sample:

 public static T GetEnum<T>(string model)
    {
        var newModel = GetStringForEnum(model);

        if (!Enum.IsDefined(typeof(T), newModel))
        {
            return (T)Enum.Parse(typeof(T), "None", true);
        }

        return (T)Enum.Parse(typeof(T), newModel.Result, true);
    }

    private static Task<string> GetStringForEnum(string model)
    {
        return Task.Run(() =>
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 -]");
            var nonAlphanumericData = rgx.Matches(model);
            if (nonAlphanumericData.Count < 1)
            {
                return model;
            }
            foreach (var item in nonAlphanumericData)
            {
                model = model.Replace((string)item, "");
            }
            return model;
        });
    }

In this sample you can send every string, and set your Enum. If your Enum had data that you wanted, return that as your Enum type.


        <Extension()>
    Public Function ToEnum(Of TEnum)(ByVal value As String, ByVal defaultValue As TEnum) As TEnum
        If String.IsNullOrEmpty(value) Then
            Return defaultValue
        End If

        Return [Enum].Parse(GetType(TEnum), value, True)
    End Function

public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}

참고URL : https://stackoverflow.com/questions/16100/convert-a-string-to-an-enum-in-c-sharp

반응형