IT

C #에서 열거 형을 문자열과 연관

lottoking 2020. 3. 19. 08:30
반응형

C #에서 열거 형을 문자열과 연관


열거 형의 유형이 int 여야하기 때문에 다음이 불가능하다는 것을 알고 있습니다.

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

내 데이터베이스에서 포괄적 인 코드 ( OEMCMBs) 가있는 필드를 얻습니다 . 이 분야를 enum이해하기 쉬운 것으로 만들고 싶습니다 . 대상이 가독성이면 솔루션이 간결해야합니다.

다른 옵션이 있습니까?


더 열거 형처럼 보이기 때문에 메서드 대신 클래스에서 속성 을 사용 하고 싶습니다.

로거의 예는 다음과 같습니다.

public class LogCategory
{
 private LogCategory(string value) { Value = value; }

 public string Value { get; set; }

 public static LogCategory Trace { get { return new LogCategory("Trace"); } }
 public static LogCategory Debug { get { return new LogCategory("Debug"); } }
 public static LogCategory Info { get { return new LogCategory("Info"); } }
 public static LogCategory Warning { get { return new LogCategory("Warning"); } }
 public static LogCategory Error { get { return new LogCategory("Error"); } }
}

으로 이동 형태 보증 된 문자열 값 매개 변수로 :

public static void Write(string message, LogCategory logCategory)
{
   var log = new LogEntry { Message = message };
   Logger.Write(log, logCategory.Value);
}

용법:

Logger.Write("This is almost like an enum.", LogCategory.Info);

확장 모델을 사용할 수도 있습니다.

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

확장 수업

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

용법:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());

상수가있는 정적 클래스를 사용하는 것은 어떻습니까? 클라이언트 코드는 열거 형과 다르지 않습니다.

static class GroupTypes
{
  public const string TheGroup = "OEM";
  public const string TheOtherGroup = "CMB";
}

void DoSomething(GroupTypes groupType)
{
  if(groupType == GroupTypes.TheOtherGroup)
  {
    //Launch nuclear bomb 
  }  
}

열거 형의 항목에 특성을 추가 한 다음 리플렉션을 사용하여 특성에서 값을 가져올 수 있습니다.

속성을 적용하려면 "field"지정자를 사용해야합니다.

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

그런 다음 열거 형 유형의 정적 필드 (이 경우 GroupTypes) DescriptionAttribute를 반영하고 리플렉션을 사용하여 찾고 있던 값을 가져옵니다 .

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);

    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");

    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);

    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);

    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

DescriptionAttribute속성이 적용되는지 여부를 결정할 수있는 경우 위의 내용 을 반환하기로 선택했습니다 .


실제로 매우 쉽게 할 수 있습니다. 다음 코드를 사용하십시오.

enum GroupTypes
{
   OEM,
   CMB
};

그런 다음 각 열거 형 요소의 문자열 값을 얻으려면 다음 코드 줄을 사용하십시오.

String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);

나는 과거 에이 방법을 성공적으로 사용했으며 상수 상수 클래스를 사용하여 문자열 상수를 유지했지만 둘 다 잘 작동하지만 선호하는 경향이 있습니다.


다음을 포함하는 DB에 대한 두 번째 열거 형을 작성하십시오.

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

이제 Enum.Parse를 사용하여 문자열 "OEM"및 "CMB"에서 올바른 DBGroupTypes 값을 검색 할 수 있습니다. 그런 다음 해당 값을 int로 변환하고 모델에서 추가로 사용하려는 올바른 열거에서 올바른 값을 검색 할 수 있습니다.


수업을 사용하십시오.

편집 : 더 나은 예

class StarshipType
{
    private string _Name;
    private static List<StarshipType> _StarshipTypes = new List<StarshipType>();

    public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
    public static readonly StarshipType Light = new StarshipType("Light");
    public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
    public static readonly StarshipType Heavy = new StarshipType("Heavy");
    public static readonly StarshipType Superheavy = new StarshipType("Superheavy");

    public string Name
    {
        get { return _Name; }
        private set { _Name = value; }
    }

    public static IList<StarshipType> StarshipTypes
    {
        get { return _StarshipTypes; }
    }

    private StarshipType(string name, int systemRatio)
    {
        Name = name;
        _StarshipTypes.Add(this);
    }

    public static StarshipType Parse(string toParse)
    {
        foreach (StarshipType s in StarshipTypes)
        {
            if (toParse == s.Name)
                return s;
        }
        throw new FormatException("Could not parse string.");
    }
}

정적 클래스에 상수를 추가하십시오. Type으로 끝나지 않지만 읽을 수 있고 체계적인 상수가 있습니다.

public static class GroupTypes {

    public const string TheGroup = "OEM";
    public const string TheOtherGroup = "CMB";

}

다음은 열거 형 값을 문자열로 얻는 데 사용한 확장 방법입니다. 먼저 여기 열거 형이 있습니다.

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

Description 속성은 System.ComponentModel에서 가져 왔습니다.

그리고 내 확장 방법은 다음과 같습니다.

public static string GetValueAsString(this DatabaseEnvironment environment) 
{
    // get the field 
    var field = environment.GetType().GetField(environment.ToString());
    var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);

    if(customAttributes.Length > 0)
    {
        return (customAttributes[0] as DescriptionAttribute).Description;  
    }
    else
    {
        return environment.ToString(); 
    }
}

이제 다음 코드를 사용하여 열거 형을 문자열 값으로 액세스 할 수 있습니다.

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}

문제를 해결하는 또 다른 방법은 열거 형 값과 문자열 목록을 매핑하는 문자열 배열을 열거하는 것입니다.

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

string[] GroupTypesStr = {
    "OEM",
    "CMB"
};

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

Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);

CMB를 프롬프트합니다

장점 :

  1. 쉽고 깨끗한 코드.
  2. 고성능 (특히 클래스를 사용하는 접근 방식과 비교)

단점 :

  1. 목록을 편집 할 때 목록이 엉망이 되기는하지만 짧은 목록은 괜찮습니다.

사전을 사용하여 찾아보기 테이블을 고려 했습니까?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

그런 다음 GroupTypeLookup.TryGetValue ()를 사용하여 읽을 때 문자열을 찾을 수 있습니다.


C #은 열거 된 문자열을 지원하지 않지만 대부분의 경우 목록 또는 사전을 사용하여 원하는 효과를 얻을 수 있습니다.

예 : 합격 / 불합격 결과를 인쇄하려면

List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);

나는 그것을 열거 형을 피하기 위해 클래스로 만들 것입니다. 그런 다음 typehandler를 사용하면 db에서 객체를 가져올 때 객체를 만들 수 있습니다.

IE :

public class Group
{
    public string Value{ get; set; }
    public Group( string value ){ Value = value; } 
    public static Group TheGroup() { return new Group("OEM"); }
    public static Group OtherGroup() { return new Group("CMB"); }

}

사전을 만들고 코드를 키로 사용합니다.

편집 : 리버스 조회 (키 찾기)에 대한 의견을 다루는 것은별로 효과적이지 않습니다. 이것이 필요한 경우 처리 할 새 클래스를 작성합니다.


첫 번째 질문-데이터베이스 자체에 액세스 할 수 있습니까? 이것은 데이터베이스에서 정규화되어야하며, 그렇지 않으면 모든 솔루션에서 오류가 발생하기 쉽습니다. 내 경험상 "OEM"과 "CMB"로 가득 찬 데이터 필드는 "oem"과 같은 것들과 다른 '스크랩 데이터'가 시간이 지남에 따라 섞이는 경향이 있습니다. Enum과 같은 요소를 포함하는 테이블에서 훨씬 더 깨끗한 구조로 완료되었습니다.

그것이 가능하지 않다면, 나는 당신의 Enum을 만들고 당신의 문자열을 Enum으로 구문 분석하는 클래스를 만듭니다. 이것은 적어도 비표준 항목을 처리하는 데 약간의 유연성을 제공하고 Enum.Parse / Reflection / etc 등을 사용하는 해결 방법을 수행하는 것보다 오류를 잡거나 처리하는 데 훨씬 더 많은 유연성을 제공합니다. 사전은 작동하지만 사례 문제 등이 있으면 고장날 수 있습니다.

할 수 있도록 수업을 쓰는 것이 좋습니다.

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

이를 통해 DB를 변경하지 않고도 대부분의 가독성을 유지할 수 있습니다.


올바르게 이해하면 문자열에서 열거 형으로 변환해야합니다.

enum GroupTypes {
    Unknown = 0,
    OEM = 1,
    CMB = 2
}
static GroupTypes StrToEnum(string str){
    GroupTypes g = GroupTypes.Unknown;
    try {
        object o = Enum.Parse(typeof(GroupTypes), str, true);
        g = (GroupTypes)(o ?? 0);
    } catch {
    }
    return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");

원하는 경우 열거 형의 제네릭으로 더 멋지게 만들 수 있습니다.


VS 2015에서는 nameof를 사용할 수 있습니다

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

용법:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

Glennular Extension 방법을 약간만 조정하면 ENUM 이외의 다른 것에서도 확장 기능을 사용할 수 있습니다.

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

또는 Linq 사용

using System;
using System.ComponentModel;
using System.Linq;

namespace Extensions {


public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}

public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;

    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");

    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }

    private DataType(string value)
    {
        this.value = value;
    }

    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;

        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;

        return predefinedValues[key];
    }

    public string Value
    {
        get { return value; }
    }
}

@Even (via class Xpublic static X회원)이 제안한대로 몇 가지 열거 형을 구현하여 요즘 .Net 4.5부터 올바른 ToString() 방법 이 있음을 나중에 알 수 있습니다.

이제 모든 것을 열거 형으로 다시 구현하고 있습니다.


이것은 강력한 형식의 매개 변수 또는 문자열 로 사용하는 방법입니다 .

public class ClassLikeEnum
{
    public string Value
    {
        get;
        private set;
    }

    ClassLikeEnum(string value) 
    {
        Value = value;
    }

    public static implicit operator string(ClassLikeEnum c)
    {
        return c.Value;
    }

    public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
    public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}

두 개의 열거 형을 사용할 수 있습니다. 하나는 데이터베이스를위한 것이고 다른 하나는 가독성을위한 것입니다.

적은 비용으로 동기화 상태를 유지해야합니다. 값을 설정할 필요는없고 위치를 동일하게 설정하면되지만 값을 설정하면 두 열거 형이 관련되어 있고 오류가 열거 형 멤버를 다시 정렬하는 것을 막을 수 있습니다. 그리고 의견은 유지 보수 승무원이 이것들이 관련되어 있고 동기화 상태를 유지해야한다는 것을 알려줍니다.

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}

// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

그것을 사용하려면 먼저 코드로 변환하십시오.

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

그런 다음 훨씬 더 편리하게 만들고 싶다면이 유형의 열거 형에서만 작동하는 확장 기능을 추가 할 수 있습니다.

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

그러면 당신은 할 수 있습니다 :

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();

나는 기본적으로 @ArthurC의 Reflection 답변을 찾고있었습니다.

그의 답변을 약간 확장하기 위해 일반적인 기능을 사용하여 더 잘 만들 수 있습니다.

    // If you want for a specific Enum
    private static string EnumStringValue(GroupTypes e)
    {
        return EnumStringValue<GroupTypes>(e);
    }

    // Generic
    private static string EnumStringValue<T>(T enumInstance)
    {
        return Enum.GetName(typeof(T), enumInstance);
    } 

그럼 당신은 당신이 가진 모든 것을 포장 할 수 있습니다

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

또는

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic

다른 의견에 따르면, 이것이 내가 생각해 낸 것입니다. 이 방법을 사용하면 상수 값을 얻으려는 위치에 .Value를 입력하지 않아도됩니다.

다음과 같은 모든 문자열 열거 형에 대한 기본 클래스가 있습니다.

using System;
using Newtonsoft.Json;

[JsonConverter(typeof(ConstantConverter))]
public class StringEnum: IConvertible
{
    public string Value { get; set; }

    protected StringEnum(string value)
    {
        Value = value;
    }

    public static implicit operator string(StringEnum c)
    {
        return c.Value;
    }
    public string ToString(IFormatProvider provider)
    {
        return Value;
    }

    public TypeCode GetTypeCode()
    {
        throw new NotImplementedException();
    }

    public bool ToBoolean(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }
    //The same for all the rest of IConvertible methods
}

JsonConverter는 다음과 같습니다.

using System;
using Newtonsoft.Json;

class ConstantConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
        }
        else
        {
            serializer.Serialize(writer, value.ToString());
        }
    }
}

그리고 실제 문자열 열거 형은 다음과 같습니다.

public sealed class Colors : StringEnum
{
    public static Colors Red { get { return new Catalog("Red"); } }
    public static Colors Yellow { get { return new Catalog("Yellow"); } }
    public static Colors White { get { return new Catalog("White"); } }

    private Colors(string value) : base(value) { }
}

그리고 이것으로 Color를 사용하여 Value 속성을 사용하지 않고 json으로 직렬화 할 수도 있습니다.


속성에 문자열을 저장하는 것과 같은 강력한 것이 필요하지 않았습니다. 난 그냥 MyEnum.BillEveryWeek"매주 청구서"또는 MyEnum.UseLegacySystem"레거시 시스템 사용"으로 바꾸어야했습니다. 기본적으로 낙타를 사용하여 열거 형을 개별 소문자로 나눕니다.

public static string UnCamelCase(this Enum input, string delimiter = " ", bool preserveCasing = false)
{
    var characters = input.ToString().Select((x, i) =>
    {

       if (i > 0 && char.IsUpper(x))
       {
           return delimiter + x.ToString(CultureInfo.InvariantCulture);
       }
       return x.ToString(CultureInfo.InvariantCulture);

    });

    var result = preserveCasing
       ? string.Concat(characters)
       : string.Concat(characters).ToLower();

    var lastComma = result.LastIndexOf(", ", StringComparison.Ordinal);

    if (lastComma > -1)
    {
       result = result.Remove(lastComma, 2).Insert(lastComma, " and ");
    }

    return result;
}

MyEnum.UseLegacySystem.UnCamelCase() "레거시 시스템 사용"출력

여러 플래그가 설정되어 있으면 일반 영어 (마지막 쉼표 대신 "and"를 제외하고 쉼표로 구분)로 바뀝니다.

var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes;

Console.WriteLine(myCustomerBehaviour.UnCamelCase());
//outputs "bill every week, use legacy system and charge taxes"

나는 이와 같은 일을했습니다.

public enum BusinessUnits
{
    NEW_EQUIPMENT = 0,
    USED_EQUIPMENT = 1,
    RENTAL_EQUIPMENT = 2,
    PARTS = 3,
    SERVICE = 4,
    OPERATOR_TRAINING = 5
}

public class BusinessUnitService
{
    public static string StringBusinessUnits(BusinessUnits BU)
    {
        switch (BU)
        {
            case BusinessUnits.NEW_EQUIPMENT: return "NEW EQUIPMENT";
            case BusinessUnits.USED_EQUIPMENT: return "USED EQUIPMENT";
            case BusinessUnits.RENTAL_EQUIPMENT: return "RENTAL EQUIPMENT";
            case BusinessUnits.PARTS: return "PARTS";
            case BusinessUnits.SERVICE: return "SERVICE";
            case BusinessUnits.OPERATOR_TRAINING: return "OPERATOR TRAINING";
            default: return String.Empty;
        }
    }
}

이것으로 부르십시오.

BusinessUnitService.StringBusinessUnits(BusinessUnits.PARTS)

문자열 리터럴을 완전히 사용하지 않으려 고했으며 항목 설명에 공백이 필요하지 않았습니다. 더 중요한 것은 제공된 문자열이 유효한 항목인지 확인하는 메커니즘을 원했기 때문에이 솔루션을 생각해 냈습니다.

public class Seasons
{
    public static string Spring { get; }
    public static string Summer { get; }
    public static string Fall { get; }
    public static string Winter { get; }

    public static bool IsValid(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            return false;
        }

        try
        {           
            return typeof(Seasons).GetProperty(propertyName) != null;
        }
        catch
        {
            return false;
        }       
    }
}

다음은 작동 방식입니다.

void Main()
{
    string s = nameof(Seasons.Fall);
    Console.WriteLine($"Fall is valid: {Seasons.IsValid(s)}"); // true

    s = "WrongSeason";
    Console.WriteLine($"WrongSeason is valid: {Seasons.IsValid(s)}"); // false
}

IsValid ()를 기본 클래스로 리팩터링하고 리플렉션을 사용하여 유형을 읽으려고했지만 (MethodBase.GetCurrentMethod (). DeclaringType) 정적을 원했기 때문에 상속 된 유형이 아닌 기본 클래스 유형을 반환합니다. 이것에 대한 당신의 치료는 매우 환영받을 것입니다! 내가 달성하려고했던 것은 다음과 같습니다.

public  class Seasons : ConstantStringsBase
{
    // ... same
}

public  class ConstantStringsBase
{
    public static bool IsValid(string propertyName)
    {       
        return MethodBase.GetCurrentMethod().DeclaringType.GetProperty(propertyName) != null;
    }
}

@Even Mien의 답변에 따라 조금 더 나아가서 Generic으로 만들려고했지만 거의 거기에있는 것처럼 보이지만 하나의 사례는 여전히 저항하고 아마도 코드를 조금 단순화 할 수 있습니다.
누군가 내가 내가 개선 할 수있는 방법을보고 특히 문자열에서 할당 할 수 없으므로 작동하게하는 경우 여기에 게시하십시오.

지금까지 나는 다음과 같은 결과를 얻었습니다.

        Console.WriteLine(TestEnum.Test1);//displays "TEST1"

        bool test = "TEST1" == TestEnum.Test1; //true

        var test2 = TestEnum.Test1; //is TestEnum and has value

        string test3 = TestEnum.Test1; //test3 = "TEST1"

        var test4 = TestEnum.Test1 == TestEnum.Test2; //false
         EnumType<TestEnum> test5 = "TEST1"; //works fine

        //TestEnum test5 = "string"; DOESN'T compile .... :(:(

마술이 일어나는 곳 :

public abstract  class EnumType<T>  where T : EnumType<T>   
{

    public  string Value { get; set; }

    protected EnumType(string value)
    {
        Value = value;
    }


    public static implicit operator EnumType<T>(string s)
    {
        if (All.Any(dt => dt.Value == s))
        {
            Type t = typeof(T);

            ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);

            return (T)ci.Invoke(new object[] {s});
        }
        else
        {
            return null;
        }
    }

    public static implicit operator string(EnumType<T> dt)
    {
        return dt?.Value;
    }


    public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
    {
        return (string)ct1 == (string)ct2;
    }

    public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
    {
        return !(ct1 == ct2);
    }


    public override bool Equals(object obj)
    {
        try
        {
            return (string)obj == Value;
        }
        catch
        {
            return false;
        }
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public static IEnumerable<T> All
     => typeof(T).GetProperties()
       .Where(p => p.PropertyType == typeof(T))
       .Select(x => (T)x.GetValue(null, null));



}

그런 다음 내 열거 형에 대해 이것을 선언해야합니다.

public class TestEnum : EnumType<TestEnum> 
{

    private TestEnum(string value) : base(value)
    {}

    public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
    public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}

@EvenMien에서 가져와 일부 의견에 추가했습니다. (내 자신의 유스 케이스에도 해당)

public struct AgentAction
{
    private AgentAction(string value) { Value = value; }

    public string Value { get; private set; }

    public override string ToString()
    {
        return this.Value;
    }

    public static AgentAction Login = new AgentAction("Logout");
    public static AgentAction Logout = new AgentAction("Logout");

    public static implicit operator string(AgentAction action) { return action.ToString(); }
}

이 클래스 추가

public class DatabasePreference {
    public DatabasePreference([CallerMemberName] string preferenceName = "") {
        PreferenceName = preferenceName;
    }
    public string PreferenceName;
}

이 작업은 CallerMemberName코딩을 최소화하기 위해 사용 하고 있습니다

사용 :

//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();

그것을 테스트하십시오 :

Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);

산출:

ScannerDefaultFlashLight
Scanner1dCodes

참고 URL : https://stackoverflow.com/questions/630803/associating-enums-with-strings-in-c-sharp

반응형