codememo

문자열 값으로 열거형을 정의하는 방법은?

tipmemo 2023. 9. 10. 12:17
반응형

문자열 값으로 열거형을 정의하는 방법은?

나는 다음과 같이 정의하려고 합니다.EnumCSV 또는 유사한 파일에 사용되는 유효한 공통 구분자를 추가합니다.그럼 저는 그것을 a에 묶을 것입니다.ComboBox데이터 소스이므로 Enum 정의를 추가하거나 삭제할 때마다 콤보 상자에서 아무것도 변경할 필요가 없습니다.

문제는 다음과 같은 문자열 표현을 사용하여 열거를 정의하는 방법입니다.

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

그럴 수 없습니다. 열거 값은 정수 값이어야 합니다.을 각 할 수 . 이 을여을거과다할수열각eet수할u을여과de열s거ouabreneegshh 또는 이 경우 모든 구분자가 단일 문자인 경우에는char선택사항:

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

(편집: 분명히 말씀드리지만, 당신은 할 수 없습니다.)char본을할수다만다수ee할의본n,만을ufmtegchar각 열거 값에 해당하는 적분 값을 할당하는 상수.위의본은은본e의int.)

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

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

당신은 그것을 성취할 수 있지만, 그것은 약간의 노력이 필요할 것입니다.

  1. 열거에 대한 문자열 값을 포함할 속성 클래스를 정의합니다.

  2. 속성에서 값을 반환하는 확장 메서드를 정의합니다. 예를 들어,GetStringValue(this Enum value)속성 값을 반환합니다.

  3. 그러면 이렇게 열거형을 정의할 수 있습니다.

    public enum Test : int {
        [StringValue("a")]
        Foo = 1,
        [StringValue("b")]
        Something = 2        
    } 
    
  4. Attribute Attribute에서 을 과 에서 과 을 .Test.Foo.GetStringValue();

참조: 문자열 값이 C#인 열거형

열거형에 문자열 값을 할당할 수 없는 것으로 알고 있습니다.문자열 상수가 포함된 클래스를 만들 수 있습니다.

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

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

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

:string MyValue = MyEnumClass.MyValue1;

너무 늦었는지도 모르지만, 이제 시작입니다.

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

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

이렇게 하면 UnitOf Measure의 결과 값은 KM 또는 MI가 됩니다. 이는 Andrew Whitaker의 답변에서도 확인할 수 있습니다.

enum으로는 할 수 없지만 다음과 같이 할 수 있습니다.

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

    public static string Tab = "\t";

    public static string Space = " ";
}

만 을 을 하는 입니다 만 입니다를 사용하는 입니다.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"
}

답이 늦었지만 미래에 누군가에게 도움이 될지도 모릅니다.저는 이런 문제에 대해 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";

    }
}

열거형은 기본 숫자 형식에만 기반할 수 있으므로 사용할 수 없습니다.대신 a를 사용해 볼 수 있습니다.

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

, 은 a 할 를 를 사용할 수 있습니다.Dictionary<Separator, char>아니면Dictionary<Separator, string>Separator는 일반 열거형입니다.

enum Separator
{
    Comma,
    Tab,
    Space
}

직접 현을 다루는 것보다는 좀 더 기분이 좋을 겁니다

더질문에 , 에 을 에 하는 을 를 을 할 의 과 가 인 할 을 인 에 enum.

은 과 을 할 할 은 을 과 enum names당신이 원하는 그리고 더enum valuesestring상의 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"
}

에서 문자열 값의 열거형을 만들기 위한 기본 클래스를 만들었습니다.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)
  • 에 xml 이 Intellisense 합니다 을 에서 합니다 을 이 에서 에 <completitionlist> (C# 및 VB에서 모두 작동): 즉,

Intellisense demo

설치

둘 중 하나:

  • 다음을 기반으로 하는 최신 StringEnum NuGet 패키지 설치.Net Standard 1.0그래서 실행됩니다..Net Core>= 1.0,.Net Framework>= 4.5,Mono등= 4.6등
  • 또는 다음 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

이 코드가 벤의 답변과 비슷하다는 것을 알게 되었습니다.저는 처음부터 끝까지 진심으로 썼어요.하지만 나는 그것이 몇개의 추가적인 것을 가지고 있다고 생각합니다.<completitionlist>hack, 결과 클래스는 Enum과 더 비슷하고 Parse(), NuGet 패키지 및 repo에 대한 성찰을 사용하지 않고 수신 문제와 피드백을 해결하기를 희망합니다.

여기에 있는 답변들을 바탕으로 저는 열거자의 동작을 모방하지만 다음과 같은 재사용 가능한 기본 클래스를 구현했습니다.string∙ ∙ 과 같은 다양한 합니다.다음과 같은 다양한 작업을 지원합니다.

  1. 가능한 값 목록 가져오기
  2. 문자열로 변환
  3. 다음을 통해 다른 인스턴스와 비교.Equals,==,그리고.!=
  4. JSON을 사용하여 JSON으로/JSON에서 변환합니다.NET 제이슨 컨버터

전체 기본 클래스는 다음과 같습니다.

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

그리고 이것은 당신이 당신의 "string enum"을 구현하는 방법입니다.

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

누군가 이것이 유용하다고 생각했으면 좋겠습니다!

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

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

스트링 타입을 허용하는 것과 같이 좀 더 우아한 해결책이 있었으면 좋겠습니다.enum언어 수준에서는 아직 지원되지 않는 것 같습니다.아래 코드는 기본적으로 다른 답변과 동일한 아이디어이지만, 더 짧고 재사용이 가능하다고 생각합니다.당신이 해야 할 일은 단지 A를 추가하는 것입니다.[Description("")]enum입력하고 10줄로 구성된 클래스를 추가합니다.

클래스:

public static class Extensions
{
    public static string ToStringValue(this Enum en)
    {
        var type = en.GetType();
        var memInfo = type.GetMember(en.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        var stringValue = ((DescriptionAttribute)attributes[0]).Description;
        return stringValue;
    }
}

용도:

    enum Country
    {
        [Description("Deutschland")]
        Germany,
        [Description("Nippon")]
        Japan,
        [Description("Italia")]
        Italy,
    }

    static void Main(string[] args)
    {
        Show(new[] {Country.Germany, Country.Japan, Country.Italy});

        void Show(Country[] countries)
        {
            foreach (var country in countries)
            {
                Debug.WriteLine(country.ToStringValue());
            }
        }
    }

자, 우선 문자가 한 문자일지라도 문자가 아닌 문자열을 할당하려고 합니다."," 대신 ','를 사용합니다. 다음으로, enums는 정수형만 사용합니다.char유니코드 값을 사용할 수도 있지만, 그렇게 하지 말 것을 강력히 권합니다.만약 당신이 이 가치들이 동일하게 유지된다는 것을 확신한다면, 다른 문화와 언어에서, 저는 문자열이 있는 정적 클래스를 사용할 것입니다.

하는 은 합니다 를 를 사용하는 것은 정말 합니다.char아니면.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();
}

이제 모든 enum의 키 값 쌍과 설명 목록이 표시됩니다.이제 콤보박스의 데이터 소스로 간단히 할당해 보겠습니다.

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

사용자는 열거형의 모든 문자열 표현을 보게 되고 코드 내에서 원하는 열거형 값을 얻게 됩니다.

여기에 답 중 일부가 숫자를 사용하는 요점을 놓치고 있으므로 더 많은 것을 추가하는 것입니다.당연히 하나의 옵션은 정적 변수 등으로 문자열을 잘 정의하는 것이지만, 잘못된 값에 대해서도 인터페이스를 여는 것입니다. 즉, 입력의 유효성을 확인해야 합니다.enum을 사용하면 허용된 값만 사용자 인터페이스로 전달됩니다.

enum Separator
{
    Comma,
    Tab,
    Space,
    CRLF,
    SoFunny
}

이 외에도 매핑 목적으로 내부 사전을 사용할 수 있습니다.

    private readonly Dictionary<Separator, string> separatorMap = new Dictionary<Separator, string>()
    {
        { Separator.Comma, "," },
        { Separator.Tab, "\t" },
        { Separator.Space, " " },
        { Separator.CRLF, "\r\n" },
        { Separator.SoFunny, "Your Mom" }
    };

이를 위한 보다 정교한 방법은 정적 클래스를 만들어 열거형에 새로운 기능을 제공하고 매핑을 처리하는 것입니다.

위의 코드를 사용하는 예는 다음과 같습니다.

public string TransformToSingleString(List<string> values, Separator separator)
{
    var separateWith = separatorMap[separator];
    ...
}

열거 클래스

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

열거형을 문자열 유형으로 정의할 수 없습니다.열거형에 대해 승인된 형식은 바이트, 바이트, 짧은, usshort, int, unint, long 또는 ulong입니다.

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

@narendras1414

저한테는 효과가 있어요.

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

언급URL : https://stackoverflow.com/questions/8588384/how-to-define-an-enum-with-string-value

반응형