Как определить перечисление со строковым значением?

Я пытаюсь определить Enum и добавить действительные общие разделители, которые используются в CSV или подобных файлах. Затем я привяжу его к ComboBox как источнику данных, поэтому всякий раз, когда я добавляю или удаляю определение Enum, мне не нужно ничего менять в поле со списком.

Проблема в том, как я могу определить перечисление со строковым представлением, например:

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

Ответ 1

Вы не можете - значения перечисления должны быть целыми значениями. Вы можете либо использовать атрибуты для связывания строкового значения с каждым значением перечисления, либо в этом случае, если каждый разделитель является единственным символом, вы можете просто использовать значение char:

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

(EDIT: просто для уточнения, вы не можете сделать char базовый тип перечисления, но вы можете использовать константы char для назначения целочисленного значения, соответствующего каждому значению перечисления. перечисление int.)

Затем добавьте метод расширения, если он вам нужен:

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

Ответ 2

Насколько я знаю, вам не будет разрешено назначать строковые значения для перечисления. Вы можете создать класс со строковыми константами в нем.

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

Ответ 3

Вы можете достичь этого, но потребуется немного работы.

  • Определите класс атрибута, который будет содержать строковое значение для перечисления.
  • Определите метод расширения, который вернет значение из атрибута. Eg..GetStringValue(это значение Enum) вернет значение атрибута.
  • Затем вы можете определить перечисление, подобное этому.
public enum Test : int {
    [StringValue("a")]
    Foo = 1,
    [StringValue("b")]
    Something = 2        
} 
  1. Чтобы вернуть значение из Attrinbute Test.Foo.GetStringValue();

Refer: Enum With String Значения в С#

Ответ 4

Вы не можете сделать это с перечислениями, но вы можете сделать это следующим образом:

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

    public static string Tab = "\t";

    public static string Space = " ";
}

Ответ 5

Для простого перечисления строковых значений (или любого другого типа):

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

Использование: string MyValue = MyEnumClass.MyValue1;

Ответ 6

Вы не можете, потому что перечисление может быть основано только на примитивном числовом типе. Вместо этого вы можете использовать Dictionary:

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

В качестве альтернативы вы можете использовать Dictionary<Separator, char> или Dictionary<Separator, string>, где Separator - нормальное перечисление:

enum Separator
{
    Comma,
    Tab,
    Space
}

что было бы немного приятнее, чем напрямую обращаться с строками.

Ответ 7

Класс, который эмулирует поведение enum, но использует 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"
}

Ответ 8

Это отчасти поздно для ответа, но, возможно, это помогает кому-то в будущем. Мне было проще использовать структуру для этой проблемы.

Следующий образец - это скопированная часть из кода 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";

    }
}

Ответ 9

Для тех, кто приезжает сюда и ищет ответ на более общий вопрос, вы можете расширить концепцию статического класса, если хотите, чтобы ваш код выглядел как enum.

Следующий подход работает, когда вы не завершили enum names, а enum values являются string представлением имени 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"
}

Ответ 10

Ну сначала вы пытаетесь назначить строки не символы, даже если они всего лишь один символ. используйте ',' вместо ",". Далее, перечисления принимают только целые типы без char, вы можете использовать значение unicode, но я бы настоятельно советовал вам не делать этого. Если вы уверены, что эти значения остаются неизменными, в разных культурах и языках я бы использовал статический класс со строками const.

Ответ 11

Пока невозможно использовать 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();
}

Теперь у вас будет список пар ключевых значений всех перечислений и их описание. Поэтому просто назначьте это как источник данных для поля со списком.

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

Пользователь видит все строковые представления перечисления и внутри вашего кода вы получите желаемое значение перечисления.

Ответ 12

Основываясь на некоторых ответах здесь, я реализовал многократно используемый базовый класс, который имитирует поведение перечисления, но со string в качестве базового типа. Он поддерживает различные операции, включая:

  1. получение списка возможных значений
  2. преобразование в строку
  3. сравнение с другими экземплярами через .Equals, == и !=
  4. преобразование в/из JSON с использованием JSON.NET JsonConverter

Это базовый класс в целом:

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

Я надеюсь, что кто-то найдет это полезным!

Ответ 13

Мы не можем определить перечисление как тип строки. Утвержденными типами перечисления являются байт, sbyte, short, ushort, int, uint, long или ulong.

Если вам нужна дополнительная информация о перечислении, пожалуйста, перейдите по ссылке ниже, эта ссылка поможет вам понять перечисление. Перечисление

@narendras1414

Ответ 14

Это работает для меня..

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

Ответ 15

Я недавно начал использовать кортежи

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

Ответ 16

Я создал базовый класс для создания строковых перечислений в .NET. Это всего лишь один файл С#, который вы можете скопировать & вставьте в свои проекты или установите через пакет NuGet с именем StringEnum.

Использование:

///<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 выглядит несколько похожим на обычный enum:
    // 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>. (Работает как в С#, так и в 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 only supported in NETStandard >= 2.0

            if (field == null)
                return null;

            return field;
        }
    }
  • Для поддержки сериализации Newtonsoft.Json скопируйте эту расширенную версию. StringEnum.cs

Я понял после того, что этот код похож на ответ бена. Я искренне написал это с нуля. Однако я думаю, что у него есть несколько дополнений, таких как хак <completitionlist>, получившийся класс больше похож на Enum, без использования отражения Parse(), пакета NuGet и репозитория, где, я надеюсь, я буду решать возникающие проблемы и отзывы.

Ответ 17

Класс 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();
}