web-dev-qa-db-ja.com

文字列値で列挙型を定義するには?

Enumを定義し、CSVまたは同様のファイルで使用される有効な共通セパレーターを追加しようとしています。次に、データソースとしてComboBoxにバインドするので、Enum定義に追加または削除するたびに、コンボボックスで何も変更する必要はありません。

問題は、次のような文字列表現で列挙型をどのように定義できるかです。

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

75
Saeid Yazdani

できません-列挙値は整数値でなければなりません。属性を使用して文字列値を各列挙値に関連付けることができます。この場合、すべての区切り文字が単一の文字である場合は、単にchar値を使用できます。

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

(編集:明確にするために、charを列挙型の基本型にすることはできませんが、char定数を使用して各列挙値に対応する整数値を割り当てることができます。上記の列挙型の基本型はintです。)

次に、必要な場合は拡張メソッド:

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

私の知る限り、文字列値を列挙型に割り当てることはできません。できることは、文字列定数を含むクラスを作成することです。

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

あなたはそれを達成することができますが、少しの作業が必要になります。

  1. Enumの文字列値を含む属性クラスを定義します。
  2. 属性から値を返す拡張メソッドを定義します。たとえば、GetStringValue(this Enum value)は属性値を返します。
  3. その後、次のように列挙型を定義できます。
 public enum Test:int {
 [StringValue( "a")] 
 Foo = 1、
 [StringValue( "b")] 
何か= 2 
} 
  1. Attrinbute Test.Foo.GetStringValue();から値を取得するには

参照: C#の文字列値を持つ列挙

52
Amit Rai Sharma

列挙型でこれを行うことはできませんが、次のように行うことができます。

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

    public static string Tab = "\t";

    public static string Space = " ";
}
24
Fischermaen

文字列値(またはその他の型)の単純な列挙型の場合:

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

使用法:string MyValue = MyEnumClass.MyValue1;

22
Thierry

列挙型はプリミティブな数値型にのみ基づいているため、できません。代わりに 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
}

これは、文字列を直接処理するよりも少し快適です。

12
Adam

列挙型の動作をエミュレートするが、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"
}
6
colmde

答えに少し遅れていますが、将来誰かを助けるかもしれません。この種の問題には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";

    }
}
5
suchoss

より一般的な質問への回答を求めてここに来ている人のために、コードをenumのように見せたい場合は、静的クラスの概念を拡張できます。

以下のアプローチは、必要なenum namesを確定しておらず、enum valuesenam namestring表現である場合に機能します。 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"
}
3
Zodman

charまたはstringをenumのベースとして使用することは実際には不可能ですが、これはあなたが本当にやりたいことではないと思います。

あなたが述べたように、可能性の列挙を持ち、コンボボックス内にこれの文字列表現を表示したいと思います。ユーザーがこれらの文字列表現のいずれかを選択した場合、対応する列挙型を取得します。そして、これは可能です:

まず、文字列を列挙値にリンクする必要があります。これは、 here または here で説明されているように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());
}

ユーザーには列挙型のすべての文字列表現が表示され、コード内で目的の列挙型値を取得できます。

2
Oliver

まず、文字が1文字であっても、文字ではなく文字列を割り当てようとします。 「、」の代わりに「、」を使用します。次に、enumはcharのない整数型のみを取ります。Unicode値を使用できますが、そうしないことを強くお勧めします。これらの値が異なる文化や言語で同じままであることを確信している場合、私はconst文字列を持つ静的クラスを使用します。

2
dowhilefor

ここでいくつかの答えに基づいて、列挙型の動作を模倣する再利用可能な基本クラスを実装しましたが、基になる型は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
Ben

列挙を文字列型として定義することはできません。列挙型の承認されたタイプは、byte、sbyte、short、ushort、int、uint、long、またはulongです。

列挙の詳細が必要な場合は、以下のリンクに従ってください。そのリンクは列挙を理解するのに役立ちます。 列挙

しゅう

0
Narendra1414

わたしにはできる..

   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
Rakesh Kr - Rkh