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


361

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

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

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

다른 옵션이 있습니까?



12
왜 대부분의 답변이 "const string"을 사용하지 않고 대신 사용자 정의 클래스를 만들고 있는지 잘 모르겠습니다.
CTS_AE

1
문자열을 사용하지 못할 수도 있지만 문자를 잘 사용할 수 있습니다. 단일 문자 값을 사용할 수있는 경우 옵션입니다.
T. Sar

1
CTS_AE가 위에서 제안한 솔루션이 왜 상위 3 대 답변에 못 미치는지에 대해서는 정말로 혼란 스러웠습니다.
Sinjai

@Sinjai 관련 값을 명시 적으로 그룹화하면 특히 API 또는 재사용 가능한 구성 요소에서 눈에 띄지 않는 성능 손실이 발생합니다.
person27

답변:


402

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

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

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);

4
내가 생각해 낼 수있는 단점은 조금 느리다는 것입니다. 그러나 이것은 대부분 무시할 수 있습니다. 그리고 편집기에서 똑같은 동작을하지 않을 것입니다. EG :이 스위치를 전환해도 각 가능성에 대한 사례가 자동으로 채워지지는 않습니다. 그 사소한 점 외에는 이것이 아마도 간단한 해결책이라고 생각합니다.
Boris Callens

3
또한 Dictionary <LogCategory, Action / Func>를 스위치로 사용하기 쉽습니다. :)
Arnis Lapsa

4
@ArnisL. 키로 작동하기에는 충분하지 않으며 Equals () 및 GetHashCode ()를 재정의해야하며 Value 속성 setter를 비공개로 설정하려고합니다. 여전히 열거 형이 아닙니다.
Dave Van den Eynde

21
내 자신의 사용을 위해이 개념을 확장하여 ToString반환 하는 메소드를 재정의했습니다 Value. 그런 다음 문자열에 암시 적 캐스트 연산자를 제공했습니다. public static implicit operator String(LogCategory category) { return Value; }.
Zarepheth

6
스위치 케이스에서 이것을 사용하는 것은 어떻습니까?
David

176

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

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());

3
다른 확장 및 설명을 위해 문자열에서 열거 형까지 stackoverflow.com/questions/4367723/… 도 참조하십시오 .
Dave

14
텍스트를 표시 할 때마다 열거 형을 반영하면 성능 측면에서 고통 스럽습니다.
Liath

4
@Liath-`.ToString ()`은 이미 리플렉션을 사용하고 있으므로,이 접근법으로 아무것도 잃지 않고 가독성을 얻지 못합니다
James King

1
모든 Enum에 자동으로 적용되도록 Extension을 일반화 할 수 있습니까?
erosebe

3
일반을 만들려면을 public static string ToDescriptionString(this Enum ...명시 적으로 입력하지 않고을 사용하십시오 MyEnum.
LeeCambl

100

상수가있는 정적 클래스를 사용하는 것은 어떻습니까?

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

void DoSomething(string groupType)
{
  if(groupType == GroupTypes.TheGroup)
  {
    // Be nice
  }  
  else if (groupType == GroupTypes.TheOtherGroup)
  {
    // Continue to be nice
  }
  else
  {
    // unexpected, throw exception?
  }
}

9
동의했다. 결과 "열"을 전환 할 수있는 것을 제외하고는보다 복잡한 솔루션의 목적을 찾는 데 어려움을 겪고 있습니다.
fakeleft

@fakeleft 당신은 제네릭 형식 (템플릿)과 함께 정적 클래스 유형을 사용할 수 없으며 다른 제한 사항이 있기 때문에 사람들이 "더 복잡한"솔루션을 선호하는 이유라고 생각합니다.
eselk

2
이 기능을 사용하려면 상수가 내부 또는 공용
이어야

46
정적 유형은 매개 변수로 사용할 수 없습니다.
Pedro Moreira

2
@PedroMoreira가 지적했듯이 GroupTypes정적 클래스이기 때문에 인수 유형으로 전달할 수 없습니다 . 그것이 미엔조차도 해결하는 문제입니다. 이 경우 대신이해야 할 것 void DoSomething(string groupType)그 다음 어떤 수단을 groupType가질 수있다 어떠한 문자열 값을 당신이 그 유효하지 않은 유형에 대비해야하고이를 처리하는 방법을 결정하는 수단도 값은 당신이 기대되지 않는다는을, (예를 들어, 예외를 던져서). Mien의 답변조차도 유효한 입력 수를 LogCategory클래스가 정의한 옵션으로 제한하여 문제를 해결합니다 .
Pharap

30

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

속성을 적용하려면 "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속성이 적용되는지 여부를 결정할 수있는 경우 위의 내용 을 반환하기로 선택했습니다 .


좀 더 복잡한 상황에서는 이것을 기억할 것이지만, OP에서 언급 한 것의 복잡성 수준을 가진 상황에서는 다소 복잡합니다
Boris Callens

26

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

enum GroupTypes
{
   OEM,
   CMB
};

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

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

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


나는 똑같은 생각을하고 있었지만 이것에주의를 기울여야합니다 ... 그렇지 않으면 더 많은 사람들이 이것을 제안 할 것으로 의심됩니다 (아마도 나는 편집증입니다).
Matthijs Wessels

내가 알고있는 유일한 캐치는 리플렉션을 사용하여 문자열을 파악한다는 것입니다. 결과적으로 상수 문자열을 추적하는 솔루션을 따르는 경우 일반적으로 클래스를 사용하여 대부분의 상수 문자열을 저장합니다. 그러나 Enum이 올바른 솔루션 인 상황 (내 Enum 요소에 대한 설명 문자열을 가져 오는 것과 상관없이)을 관리하기 위해 어딘가에 떠있는 여분의 문자열을 사용하는 대신 설명 된대로 열거 형 값을 사용합니다.
Arthur C

+1 이것은 가장 쉽고 쉬운 답변이며, 여기에서 이를 증명하기 위해 높은 투표 를 받았습니다. 확장 모델 을 사용 하는 것이 텍스트에 공백이 필요할 때 뿐입니다 (자세한 내용은 여기 참조 ).
SharpC

14
아니요, 열거 형 값에 문자열을 할당하지 않고 열거 형 값의 이름을 가져옵니다. OP의 목표는 열거 형 값과 다른 문자열을 갖는 것입니다. 예 : TheGroup = "OEM", TheOtherGroup = "CMB".
Tim Autin

3
@Tim의 의견에 동의합니다. 이것은 OP 가하려 는 것이 아닙니다 . 유스 케이스가 무엇인지 궁금하다면 장치가 문자열을 명령으로 사용하지만 "사람이 읽을 수있는"버전의 명령이 필요한 상황을 고려하십시오. "Update Firmware"와 같은 명령을 "UPDATEFW"명령과 연결하려면이 기능이 필요했습니다.
JYelton

20

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

public static class GroupTypes {

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

}

3
코드에서 설명적인 이름으로 돌아 가기가 어렵습니다. 일치하는 항목을 검색하려면 모든 const 필드에 반영을 사용해야합니다.
andleer

1
@andleer 귀하의 우려를 이해하지 못합니다. 이것이 내가 사용하는 솔루션입니다.
VSO

예, 이것은 실제로 내가 원하는 것입니다. 그리고 이것은 int 값으로 열거를 정의하는 것처럼 문자열 값을 사용하는 것처럼 가장 간결하고 우아한 솔루션입니다. 100 % 완벽합니다.
차드

3
이것의 문제는 유한 값 목록을 가진 별도의 유형이 없다는 의미에서 Enum으로 작동하지 않는다는 것입니다. 이를 기대하는 함수는 오류가 발생하기 쉬운 자유형 문자열과 함께 사용할 수 있습니다.
Juan Martinez

14

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

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

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


이것은 프로세스의 추가 단계 인 것 같습니다. 왜 모든 클래스를 처리하는 클래스가 아닌가?
C. Ross

11
속성과 반사를 사용하는 것과 반대로?
Dave Van den Eynde

13

수업을 사용하십시오.

편집 : 더 나은 예

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.");
    }
}

1
코드에서 설명적인 이름으로 돌아 가기가 어렵습니다. 일치하는 항목을 검색하려면 모든 const 필드에 리플렉션을 사용해야합니다.
andleer

1
너의 의도를 알 겠어. 나중에 잘 작동하는 버전을 업로드 할 것이지만 꽤 무겁다는 것을 인정합니다.
C. Ross

C. Ross의 솔루션을 기반으로 한 내 버전 stackoverflow.com/a/48441114/3862615
Roman M

7

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

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

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

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

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

CMB를 프롬프트합니다

장점 :

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

단점 :

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

6

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

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());  
    }
}

5

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

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 ()를 사용하여 읽을 때 문자열을 찾을 수 있습니다.


주어진 가치에 대한 열쇠를 어떻게 쉽게 얻습니까?
eglasius

그 질문은 다른 방향으로 가라고 요구하지 않았습니다. 그러나 다른 방식으로 진행되는 다른 사전을 작성하는 것은 간단합니다. 즉, Dictionary <GroupTypes, string>입니다.
Jim Mischel 2016 년

4
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; }
    }
}

3

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

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

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

2

나는 그것을 열거 형을 피하기 위해 클래스로 만들 것입니다. 그런 다음 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"); }

}

2

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

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


또한 주어진 가치에 대한 열쇠를 쉽게 잡을 수 있습니까?
eglasius

C.Ross에게-당신이 무슨 뜻인지 모르겠습니다. db에서 값을 읽고 사전을 동적으로 채울 수 있습니다.
jhale 2016 년

2

첫 번째 질문-데이터베이스 자체에 액세스 할 수 있습니까? 이것은 데이터베이스에서 정규화되어야하며, 그렇지 않으면 모든 솔루션에서 오류가 발생하기 쉽습니다. 내 경험상, "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를 변경하지 않고도 대부분의 가독성을 유지할 수 있습니다.


2

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

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");

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


2

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));

2

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;  
    }
}

2

@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"); } }
}

이 위대한 일에 감사드립니다, 나는 오랫동안 그러한 접근 방식을 찾고있었습니다. 나는 이것을 위해 1000 포인트를 얻어야한다고 생각한다
user3492977

이 의견을 보내 주셔서 감사합니다.이 사실을 상기시켜 주셔서 감사합니다.이 코드를 작성할 때 2 년 동안 C #을 사용하지 않았습니다. 곧 다시 연락해야합니다!
Lomithrani

@ user3492977 나는 마침내 다시되었고, 완전히, 난 여전히 의심 functionnal 생각했다가 좋은 아이디어 또는 쓸모없는 일이 있다면 생각 : D stackoverflow.com/questions/62043138/...
Lomithrani

2

.Net Core 3.0 / C # 8.0의 새로운 기능 (작업 환경에서 프로젝트를 업그레이드 할 수있는 경우)은 간단한 전환 설명입니다. 하루가 끝나면 몇 년 동안 사용했던 것과 같은 오래된 지루한 스위치 설명입니다.

여기서 유일한 차이점은 switch 문이 새로운 소송을 받았다는 것입니다.

public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
    Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
    Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
    Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
    Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
    Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
    Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
    Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
    _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};

당신은 내가 복사하는 위의 코드 것을 알 수 있습니다 여기가 실제로 PARAM으로 열거를 사용하고 있습니다.

그것은 정확히 당신이 원하는 것이 아니며 (그리고 OP, 오랫동안 OP가 요청하는 것과 비슷한 것을 원했습니다) 실제로는 이것이 MS의 올리브 가지라고 생각합니다. JMO.

그것이 누군가를 돕기를 바랍니다!


2

이전 답변에서 언급 한 구조를 사용했지만 복잡성을 제거했습니다. 나에게 이것은 문자열 열거를 만드는 것과 가장 비슷했습니다. 열거 형과 같은 방식으로 사용됩니다.

    struct ViewTypes
    {
        public const string View1 = "Whatever string you like";
        public const string View2 = "another string";
    }

사용 예 :

   switch( some_string_variable )
   {
      case ViewTypes.View1: /* do something */ break;
      case ViewTypes.View2: /* do something else */ break;
   }

1

@Even (via class Xpublic static X회원)이 제안한대로 몇 가지 열거 형을 구현했습니다. 요즘 .Net 4.5부터는 옳습니다. ToString() 방법 있습니다.

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


1

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

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");
}

1

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

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

// 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();

그것은 나쁜 습관이다 : 의존에 enum따라 의도 된 가치 변화는 무의식적으로 다른 것을 망칠 수있다.
Lorenz Lo Sauer

1

나는 기본적으로 @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

1

@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(); }
}

1

이 클래스 추가

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

0

다른 의견에 따르면, 이것이 내가 생각해 낸 것입니다. 이 방법은 상수 값을 얻으려는 경우 .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으로 직렬화 할 수도 있습니다.


0

속성에 문자열을 저장하는 것과 같은 강력한 것이 필요하지 않았습니다. 난 그냥 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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.