문자열 값으로 열거 형을 정의하는 방법은 무엇입니까?


97

EnumCSV 또는 유사한 파일에 사용되는 유효한 공통 구분 기호 를 정의 하고 추가 하려고 합니다. 그런 다음 ComboBoxEnum 정의에서 추가하거나 제거 할 때마다 콤보 상자에서 아무것도 변경할 필요가 없도록 데이터 소스로 바인딩 할 것입니다.

문제는 다음과 같이 문자열 표현으로 열거 형을 정의하는 방법입니다.

public enum SeparatorChars{Comma = ",", Tab = "\t", Space = " "}


답변:


113

당신은 할 수 없습니다-열거 형 값은 정수 값이어야합니다. 속성을 사용하여 문자열 값을 각 열거 형 값과 연결하거나이 경우 모든 구분 기호가 단일 문자 인 경우 char값을 사용할 수 있습니다 .

enum Separator
{
    Comma = ',',
    Tab = '\t',
    Space = ' '
}

(편집 : 명확히하기 위해 char열거 형의 기본 유형을 만들 수 는 없지만 char상수를 사용 하여 각 열거 형 값에 해당하는 정수 값을 할당 할 수 있습니다 . 위 열거 형의 기본 유형은입니다 int.)

그런 다음 필요한 경우 확장 방법 :

public string ToSeparatorString(this Separator separator)
{
    // TODO: validation
    return ((char) separator).ToString();
}

Char는 열거 형에서 유효하지 않습니다. Msdn : "모든 열거 유형에는 기본 유형이 있으며 char을 제외한 모든 정수 유형이 될 수 있습니다."
dowhilefor dec

8
@dowhilefor : 내 대답 에 따라 값에 문자 리터럴을 사용할 수 있습니다 . 나는 그것을 :) 테스트
존 소총을

이 요구 사항은 파일에 대한 것이므로 사용자는 CRLF 구분 기호가 필요할 수 있습니다. 이 경우에도 작동합니까?
Maheep

감사합니다 Jon, \ t는 문자로 간주됩니까?!
Saeid Yazdani

1
@ShaunLuttin : 열거 형은 "이름이 지정된 숫자"일뿐입니다. 따라서 문자열 열거 형은 실제로 해당 모델에 전혀 맞지 않습니다.
Jon Skeet

83

내가 아는 한 enum에 문자열 값을 할당 할 수 없습니다. 당신이 할 수있는 일은 그 안에 문자열 상수가있는 클래스를 만드는 것입니다.

public static class SeparatorChars
{
    public static String Comma { get { return ",";} } 
    public static String Tab { get { return "\t,";} } 
    public static String Space { get { return " ";} } 
}

9
다른 사람과 반대되는이 접근 방식의 단점은 추가 / 특별한 작업을 수행하지 않고는이를 열거 할 수 없다는 것입니다.
caesay

이것은 제한된 유효한 값을 가진 유형 separator대신 문자열 (무엇이든 될 수 있음) 이기 때문에 컴파일 시간 동안 특정 값을 적용하는 데 도움이되지 않습니다 Separator.
ChickenFeet

73

당신은 그것을 달성 할 수 있지만 약간의 작업이 필요합니다.

  1. enum의 문자열 값을 포함 할 속성 클래스를 정의하십시오.
  2. 속성에서 값을 반환 할 확장 메서드를 정의합니다. 예 : GetStringValue (이 Enum 값)는 속성 값을 반환합니다.
  3. 그런 다음 다음과 같이 열거 형을 정의 할 수 있습니다.
공개 열거 형 테스트 : int {
    [StringValue ( "a")]
    Foo = 1,
    [문자열 값 ( "b")]
    무언가 = 2        
} 
  1. Attrinbute Test.Foo.GetStringValue ();에서 값을 반환하려면

참조 : C #에서 문자열 값이있는 열거 형


5
나는 이것이 오래되었다는 것을 알고 있지만 분명히 고유하며 DB의 코드 및 문자열 값에 열거 형을 사용할 수 있습니다. Amazing
A_kat 19 년

1
또 다른 후기 댓글이지만 이것은 정말 훌륭한 솔루션입니다
Alan

36

단순 열거 형 문자열 값 (또는 기타 유형)의 경우 :

public static class MyEnumClass
{
    public const string 
        MyValue1 = "My value 1",
        MyValue2 = "My value 2";
}

용법: string MyValue = MyEnumClass.MyValue1;


1
열거 형은 아니지만 사용자가하려는 작업에 대한 최상의 솔루션을 제공 할 수 있다고 생각합니다. 때로는 가장 간단한 해결책이 가장 좋습니다.
Zesty

29

열거 형으로는 이것을 할 수 없지만 다음과 같이 할 수 있습니다.

public static class SeparatorChars
{
    public static string Comma = ",";

    public static string Tab = "\t";

    public static string Space = " ";
}

1
+1 올바른 솔루션이라고 생각하지만 클래스 이름을 변경하거나 유형을 문자로 변경합니다. 일관성을 유지하기 위해.
dowhilefor dec

감사합니다 comboBox.DataSource = Enum.GetValues(typeof(myEnum));.이 경우 와 동등한 것이 무엇인지 말할 수 있습니까?
Saeid Yazdani

1
@ Sean87 : 나는 당신이 그것을 갖고 싶어, 나는 JonSkeets 대답을 취할 것입니다.
Fischermaen 2011

switch-case블록 내에서 사용할 수 없기 때문에 이것이 거의 정답이라고 생각합니다 . 필드는 const순서가 있어야합니다 . 그러나 원하는 경우 여전히 도움이 될 수 없습니다 Enum.GetValues(typeof(myEnum)).
André Santaló 2014 년

7
내가 사용하는 것 const대신에 static. 상수는 읽기 전용 일뿐만 아니라 정적이며 생성자에서 서명 할 수 없습니다 (읽기 전용 필드 제외).
Olivier Jacot-Descombes 2015

12

enum은 원시 숫자 유형에만 기반 할 수 있기 때문에 불가능합니다. Dictionary대신 a 를 사용해 볼 수 있습니다 .

Dictionary<String, char> separators = new Dictionary<string, char>
{
    {"Comma", ','}, 
    {"Tab",  '\t'}, 
    {"Space", ' '},
};

또는 a Dictionary<Separator, char>또는 Dictionary<Separator, string>where Separatoris a normal enum을 사용할 수 있습니다 .

enum Separator
{
    Comma,
    Tab,
    Space
}

문자열을 직접 처리하는 것보다 조금 더 즐겁습니다.


11

열거 형 동작을 에뮬레이트하지만 string대신 사용하는 클래스는 int다음과 같이 만들 수 있습니다.

public class GrainType
{
    private string _typeKeyWord;

    private GrainType(string typeKeyWord)
    {
        _typeKeyWord = typeKeyWord;
    }

    public override string ToString()
    {
        return _typeKeyWord;
    }

    public static GrainType Wheat = new GrainType("GT_WHEAT");
    public static GrainType Corn = new GrainType("GT_CORN");
    public static GrainType Rice = new GrainType("GT_RICE");
    public static GrainType Barley = new GrainType("GT_BARLEY");

}

용법...

GrainType myGrain = GrainType.Wheat;

PrintGrainKeyword(myGrain);

그때...

public void PrintGrainKeyword(GrainType grain) 
{
    Console.Writeline("My Grain code is " + grain.ToString());   // Displays "My Grain code is GT_WHEAT"
}

유일한 것은 GrainType myGrain = "GT_CORN"예를 들어 할 수 없다는 것입니다 .
colmde

연산자를
무시

8

대답하기에는 다소 늦었지만 미래에 누군가에게 도움이 될 수도 있습니다. 이런 종류의 문제에 struct를 사용하는 것이 더 쉽다는 것을 알았습니다.

다음 샘플은 MS 코드에서 붙여 넣은 부분을 복사합니다.

namespace System.IdentityModel.Tokens.Jwt
{
    //
    // Summary:
    //     List of registered claims from different sources http://tools.ietf.org/html/rfc7519#section-4
    //     http://openid.net/specs/openid-connect-core-1_0.html#IDToken
    public struct JwtRegisteredClaimNames
    {
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Actort = "actort";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Typ = "typ";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Sub = "sub";
        //
        // Summary:
        //     http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
        public const string Sid = "sid";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Prn = "prn";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nbf = "nbf";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nonce = "nonce";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string NameId = "nameid";

    }
}

수업을 이용하는 것보다이 비난이 더 나은 이유를 설명해 주시겠습니까?
Gerardo Grignoli

@GerardoGrignoli 나는 그들이 이런 종류의 일을 위해 MS에서 클래스 대신 struct를 사용하는 이유를 정확히 알지 못합니다. 이것이 나를 위해 완벽하게 작동하기 때문에 나는 알아 내려고 시도조차하지 않았습니다. 어쩌면 여기 스택에 질문을 해보세요 ...
suchoss

6

너무 늦었을 수도 있지만 여기에 있습니다.

EnumMember 속성을 사용하여 Enum 값을 관리 할 수 ​​있습니다.

public enum EUnitOfMeasure
{
    [EnumMember(Value = "KM")]
    Kilometer,
    [EnumMember(Value = "MI")]
    Miles
}

이렇게하면 EUnitOfMeasure의 결과 값이 KM 또는 MI가됩니다. 이것은 Andrew Whitaker 대답 에서도 볼 수 있습니다 .


5

좀 더 일반적인 질문에 대한 답을 찾고있는 사람들을 위해 코드가 enum.

다음 접근 방식은 enum names원하는 것을 완료하지 않았고 enum valuesstring표현이 될 때 작동 합니다 enam name. nameof()리팩토링을 더 간단하게 만드는 데 사용 합니다.

public static class Colours
{
    public static string Red => nameof(Red);
    public static string Green => nameof(Green);
    public static string Blue => nameof(Blue);
}

이렇게하면 문자열 값 (예 : 다음 의사 코드)이있는 열거 형의 의도를 얻을 수 있습니다.

public enum Colours
{
    "Red",
    "Green",
    "Blue"
}

4

.NET에서 문자열 값 열거 형을 만들기위한 기본 클래스를 만들었습니다. 프로젝트에 복사하여 붙여 넣거나 StringEnum 이라는 NuGet 패키지를 통해 설치할 수있는 단 하나의 C # 파일입니다 .

용법:

///<completionlist cref="HexColor"/> 
class HexColor : StringEnum<HexColor>
{
    public static readonly HexColor Blue = New("#FF0000");
    public static readonly HexColor Green = New("#00FF00");
    public static readonly HexColor Red = New("#000FF");
}

풍모

  • StringEnum은 일반 열거 형과 다소 유사합니다.
    // Static Parse Method
    HexColor.Parse("#FF0000") // => HexColor.Red
    HexColor.Parse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.Parse("invalid") // => throws InvalidOperationException

    // Static TryParse method.
    HexColor.TryParse("#FF0000") // => HexColor.Red
    HexColor.TryParse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.TryParse("invalid") // => null

    // Parse and TryParse returns the preexistent instances
    object.ReferenceEquals(HexColor.Parse("#FF0000"), HexColor.Red) // => true

    // Conversion from your `StringEnum` to `string`
    string myString1 = HexColor.Red.ToString(); // => "#FF0000"
    string myString2 = HexColor.Red; // => "#FF0000" (implicit cast)
  • Intellisense는 클래스에 xml 주석이 추가 된 경우 열거 형 이름을 제안합니다 <completitionlist>. (C # 및 VB 모두에서 작동) : 예

Intellisense 데모

설치

어느 한 쪽:

  • > = 1.0, > = 4.5, > = 4.6 등에서 실행되도록 기반으로하는 최신 StringEnum NuGet 패키지를 설치합니다 ..Net Standard 1.0.Net Core.Net FrameworkMono
  • 또는 다음 StringEnum 기본 클래스를 프로젝트에 붙여 넣습니다. ( 최신 버전 )
    public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
    {
        protected string Value;
        private static IList<T> valueList = new List<T>();
        protected static T New(string value)
        {
            if (value == null)
                return null; // the null-valued instance is null.

            var result = new T() { Value = value };
            valueList.Add(result);
            return result;
        }

        public static implicit operator string(StringEnum<T> enumValue) => enumValue.Value;
        public override string ToString() => Value;

        public static bool operator !=(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value != o2?.Value;
        public static bool operator ==(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value == o2?.Value;

        public override bool Equals(object other) => this.Value.Equals((other as T)?.Value ?? (other as string));
        bool IEquatable<T>.Equals(T other) => this.Value.Equals(other.Value);
        public override int GetHashCode() => Value.GetHashCode();

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else throws InvalidOperationException.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
        public static T Parse(string value, bool caseSensitive = false)
        {
            var result = TryParse(value, caseSensitive);
            if (result == null)
                throw new InvalidOperationException((value == null ? "null" : $"'{value}'") + $" is not a valid {typeof(T).Name}");

            return result;
        }

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else returns null.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
        public static T TryParse(string value, bool caseSensitive = false)
        {
            if (value == null) return null;
            if (valueList.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
            var field = valueList.FirstOrDefault(f => f.Value.Equals(value,
                    caseSensitive ? StringComparison.Ordinal
                                  : StringComparison.OrdinalIgnoreCase));
            // Not using InvariantCulture because it's only supported in NETStandard >= 2.0

            if (field == null)
                return null;

            return field;
        }
    }
  • 들어 Newtonsoft.Json직렬화 지원, 대신이 확장 버전을 복사합니다. StringEnum.cs

이 코드가 Ben의 대답과 비슷하다는 사실을 깨달았습니다. 처음부터 진심으로 썼습니다. 그러나 <completitionlist>해킹 과 같은 몇 가지 추가 사항이 있다고 생각합니다 . 결과 클래스는 Enum, Parse ()에 대한 리플렉션 사용 안 함, NuGet 패키지 및 들어오는 문제와 피드백을 해결하기를 바라는 리포지토리처럼 보입니다.


3

여기에 몇 가지 답변을 기반으로 열거 형의 동작을 모방하지만 string기본 유형으로 사용 하는 재사용 가능한 기본 클래스를 구현했습니다 . 다음을 포함한 다양한 작업을 지원합니다.

  1. 가능한 값 목록 얻기
  2. 문자열로 변환
  3. 다른 경우와 비교를 통해 .Equals, ==그리고!=
  4. JSON.NET JsonConverter를 사용하여 JSON으로 /에서 변환

이것은 전체적으로 기본 클래스입니다.

public abstract class StringEnumBase<T> : IEquatable<T>
    where T : StringEnumBase<T>
{
    public string Value { get; }

    protected StringEnumBase(string value) => this.Value = value;

    public override string ToString() => this.Value;

    public static List<T> AsList()
    {
        return typeof(T)
            .GetProperties(BindingFlags.Public | BindingFlags.Static)
            .Where(p => p.PropertyType == typeof(T))
            .Select(p => (T)p.GetValue(null))
            .ToList();
    }

    public static T Parse(string value)
    {
        List<T> all = AsList();

        if (!all.Any(a => a.Value == value))
            throw new InvalidOperationException($"\"{value}\" is not a valid value for the type {typeof(T).Name}");

        return all.Single(a => a.Value == value);
    }

    public bool Equals(T other)
    {
        if (other == null) return false;
        return this.Value == other?.Value;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        if (obj is T other) return this.Equals(other);
        return false;
    }

    public override int GetHashCode() => this.Value.GetHashCode();

    public static bool operator ==(StringEnumBase<T> a, StringEnumBase<T> b) => a?.Equals(b) ?? false;

    public static bool operator !=(StringEnumBase<T> a, StringEnumBase<T> b) => !(a?.Equals(b) ?? false);

    public class JsonConverter<T> : Newtonsoft.Json.JsonConverter
        where T : StringEnumBase<T>
    {
        public override bool CanRead => true;

        public override bool CanWrite => true;

        public override bool CanConvert(Type objectType) => ImplementsGeneric(objectType, typeof(StringEnumBase<>));

        private static bool ImplementsGeneric(Type type, Type generic)
        {
            while (type != null)
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == generic)
                    return true;

                type = type.BaseType;
            }

            return false;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken item = JToken.Load(reader);
            string value = item.Value<string>();
            return StringEnumBase<T>.Parse(value);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is StringEnumBase<T> v)
                JToken.FromObject(v.Value).WriteTo(writer);
        }
    }
}

그리고 이것은 "문자열 열거"를 구현하는 방법입니다.

[JsonConverter(typeof(JsonConverter<Colour>))]
public class Colour : StringEnumBase<Colour>
{
    private Colour(string value) : base(value) { }

    public static Colour Red => new Colour("red");
    public static Colour Green => new Colour("green");
    public static Colour Blue => new Colour("blue");
}

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

public class Foo
{
    public Colour colour { get; }

    public Foo(Colour colour) => this.colour = colour;

    public bool Bar()
    {
        if (this.colour == Colour.Red || this.colour == Colour.Blue)
            return true;
        else
            return false;
    }
}

누군가 이것이 유용하다고 생각하기를 바랍니다!


2

먼저 문자가 아닌 문자열을 지정하려고합니다. ","대신 ','를 사용하십시오. 다음으로, enum char은 유니 코드 값을 사용할 수 없는 정수 유형 만 취하지 만 그렇게하지 말라고 강력하게 조언합니다. 이러한 값이 다른 문화와 언어에서 동일하게 유지된다는 확신이 들면 const 문자열이있는 정적 클래스를 사용합니다.


2

a char또는 a string를 열거 형의 기반으로 사용하는 것은 실제로 불가능하지만 이것이 당신이 정말로 좋아하는 것이 아니라고 생각합니다.

당신이 언급했듯이 당신은 가능성의 열거 형을 갖고 콤보 상자 내에 이것의 문자열 표현을 보여주고 싶습니다. 사용자가 이러한 문자열 표현 중 하나를 선택하면 해당 열거 형을 가져 오려고합니다. 그리고 이것은 가능합니다 :

먼저 일부 문자열을 열거 형 값에 연결해야합니다. 여기 또는 여기에DescriptionAttribute 설명 된 것과 같이 사용하여이를 수행 할 수 있습니다 .

이제 열거 형 값 및 해당 설명 목록을 만들어야합니다. 다음 방법을 사용하여 수행 할 수 있습니다.

/// <summary>
/// Creates an List with all keys and values of a given Enum class
/// </summary>
/// <typeparam name="T">Must be derived from class Enum!</typeparam>
/// <returns>A list of KeyValuePair&lt;Enum, string&gt; with all available
/// names and values of the given Enum.</returns>
public static IList<KeyValuePair<T, string>> ToList<T>() where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
    {
        throw new ArgumentException("T must be an enum");
    }

    return (IList<KeyValuePair<T, string>>)
            Enum.GetValues(type)
                .OfType<T>()
                .Select(e =>
                {
                    var asEnum = (Enum)Convert.ChangeType(e, typeof(Enum));
                    return new KeyValuePair<T, string>(e, asEnum.Description());
                })
                .ToArray();
}

이제 모든 열거 형과 해당 설명의 키 값 쌍 목록이 있습니다. 따라서 이것을 콤보 상자의 데이터 소스로 지정해 보겠습니다.

var comboBox = new ComboBox();
comboBox.ValueMember = "Key"
comboBox.DisplayMember = "Value";
comboBox.DataSource = EnumUtilities.ToList<Separator>();

comboBox.SelectedIndexChanged += (sender, e) =>
{
    var selectedEnum = (Separator)comboBox.SelectedValue;
    MessageBox.Show(selectedEnum.ToString());
}

사용자는 열거 형의 모든 문자열 표현을 볼 수 있으며 코드 내에서 원하는 열거 형 값을 얻을 수 있습니다.


0

열거 형을 문자열 유형으로 정의 할 수 없습니다. 열거 형에 대해 승인 된 유형은 byte, sbyte, short, ushort, int, uint, long 또는 ulong입니다.

열거에 대한 자세한 내용이 필요하면 아래 링크를 따르십시오. 해당 링크는 열거를 이해하는 데 도움이 될 것입니다. 열거

안녕하세요.


0

저 한테 잘 맞아요 ..

   public class ShapeTypes
    {
        private ShapeTypes() { }
        public static string OVAL
        {
            get
            {
                return "ov";
            }
            private set { }
        }

        public static string SQUARE
        {
            get
            {
                return "sq";
            }
            private set { }
        }

        public static string RECTANGLE
        {
            get
            {
                return "rec";
            }
            private set { }
        }
    }

0

내가 최근에 시작한 것은 튜플을 사용하는 것입니다.

public static (string Fox, string Rabbit, string Horse) Animals = ("Fox", "Rabbit", "Horse");
...
public static (string Comma, string Tab, string Space) SeparatorChars = (",", "\t", " ");

-1

Enumaration 클래스

 public sealed class GenericDateTimeFormatType
    {

        public static readonly GenericDateTimeFormatType Format1 = new GenericDateTimeFormatType("dd-MM-YYYY");
        public static readonly GenericDateTimeFormatType Format2 = new GenericDateTimeFormatType("dd-MMM-YYYY");

        private GenericDateTimeFormatType(string Format)
        {
            _Value = Format;
        }

        public string _Value { get; private set; }
    }

에 누마 레이션 소비

public static void Main()
{
       Country A = new Country();

       A.DefaultDateFormat = GenericDateTimeFormatType.Format1;

      Console.ReadLine();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.