Numaraları C # dizeleri ile ilişkilendirme


363

Aşağıdakilerin mümkün olmadığını biliyorum çünkü Numaralandırma'nın türü bir int olmalı

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

Veritabanımdan kapsamlı kodları olan bir alan alıyorum ( OEMve CMB). Bu alanı enumanlaşılabilir bir şey haline getirmek istiyorum . Çünkü hedef okunabilirlik ise, çözüm kısa olmalıdır.

Başka hangi seçeneklerim var?



12
Yanıtların çoğunun neden sadece "const string" i kullanmadıklarından emin değilim, bunun yerine özel sınıflar yapıyorlar.
CTS_AE

1
Dizeleri kullanamayabilirsiniz, ancak karakterleri iyi kullanabilirsiniz. Tek harfli değerler kullanabiliyorsanız bu bir seçenektir.
T. Sar

1
Yukarıda CTS_AE tarafından önerilen çözümün neden ilk üç cevapta yer almadığı konusunda şaşkın.
Sinjai

@Sinjai İlgili değerlerin açık gruplanması, özellikle bir API veya yeniden kullanılabilir bileşende algılanamayan bir performans kaybının cezasından daha ağır basacaktır.
person27

Yanıtlar:


405

Daha sıra numarası gibi göründüğünden, yöntemler yerine sınıfta özelliklerini kullanmayı seviyorum.

Logger için bir örnek:

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

Aktarın tip-güvenli dize değerleri parametre olarak:

public static void Write(string message, LogCategory logCategory)
{
    var log = new LogEntry { Message = message };
    Logger.Write(log, logCategory.Value);
}

Kullanımı:

Logger.Write("This is almost like an enum.", LogCategory.Info);

4
Gelebileceğim sadece aşağı tarafı, biraz daha yavaş olacağı, ancak çoğu durumda ihmal edilebilir olacaktır. Ve editörde aynı davranışa sahip olmazdı. EG: bunu değiştirmek, her olasılık için otomatik olarak bir vakayı doldurmaz. Bu küçük noktalar dışında, bunun muhtemelen oldukça basit bir çözüm olduğunu düşünüyorum.
Boris Callens

3
Ve bir sözlük olarak Sözlük <LogCategory, Action / Func> kullanımı kolaydır. :)
Arnis Lapsa

4
@ArnisL. Anahtar olarak çalışmak yeterli değildir, Equals () ve GetHashCode () değerlerini geçersiz kılmanız gerekir ve Value özelliği ayarlayıcısını özel yapmak istersiniz. Yine de, bu bir numaralandırma değil.
Dave Van den Eynde

21
Kendi kullanımım için, ToStringgeri dönme yöntemini geçersiz kılarak bu konsepti genişlettim Value. Ve sonra bir dizgiye ve dizgiden örtülü döküm operatörleri sağladı. public static implicit operator String(LogCategory category) { return Value; }.
Zarepheth

6
Bunu anahtar kutularında kullanmaya ne dersiniz?
David

176

Uzantı modelini de kullanabilirsiniz:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

Eklenti Sınıfınız

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

kullanımı:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());

3
Ayrıca , açıklama yoluyla dizeden numaraya başka bir uzantı için stackoverflow.com/questions/4367723/… adresine bakın .
Dave

15
Her istediğinizde enum'u yansıtan metnin performans açısından biraz acı verici olduğunu düşünmeye yardımcı olamıyorum!
Liath

4
@Liath - `.ToString ()` zaten yansımayı kullanıyor, bu yüzden bu yaklaşımla gerçekten hiçbir şey kaybetmiyorsunuz ve okunabilirlik kazanıyorsunuz
James King

1
Uzantıyı tüm Numaralandırmalara otomatik olarak uygulanacak şekilde genel hale getirebilir misiniz?
erosebe

3
Genel yapmak için, public static string ToDescriptionString(this Enum ...açıkça yazmadan yani kullanın MyEnum.
LeeCambl

100

Sabitlerle statik bir sınıf kullanmaya ne dersiniz?

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
Kabul. Belki ortaya çıkan "enum" arasında geçiş yapabilmek dışında, daha karmaşık çözümlerin arkasındaki amacı görmekte sorun yaşıyorum.
fakeleft

@fakeleft, genel bir tür (şablon) ile statik bir sınıf türü kullanamazsınız ve belki de diğer sınırlamalar, bence bu yüzden insanlar "daha karmaşık" çözümleri tercih ediyor.
eselk

2
Sabitlerin bunun çalışması için dahili veya halka açık olması gerekir
arviman

46
Statik tipler parametre olarak kullanılamaz.
Pedro Moreira

2
@PedroMoreira'nın işaret ettiği GroupTypesgibi, statik bir sınıf olduğu için bağımsız değişken türü olarak geçemezsiniz . Mien'in cevabının bile çözdüğü sorun budur. Bu durumda, bunun yerine sahip olmanız gerekir void DoSomething(string groupType); bu groupTypeda, herhangi bir dize değerine , beklemediğiniz değerlere bile sahip olabileceği anlamına gelir; bir istisna atarak). Mien'in cevabı bile, geçerli girdi sayısını LogCategorysınıf tarafından tanımlanan seçeneklerle sınırlayarak çözer .
Pharap

30

Numaralandırmadaki öğelere öznitelikler ekleyebilir ve sonra özniteliklerden değerleri almak için yansımayı kullanabilirsiniz.

Nitelikleri uygulamak için "alan" belirtecini kullanmanız gerekir, şöyle:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

Daha sonra numaralandırma türünün statik alanlarını (bu durumda GroupTypes) yansıtır ve DescriptionAttributeyansıma kullanarak aradığınız değeri elde edersiniz:

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Özniteliğin uygulanıp uygulanmadığını belirleyebilmek istediğinizde, yukarıda kendisini döndürmeyi seçtim .


Bunu daha karmaşık durumlar için hatırlayacağım halde, OP'de belirttiğim şeyin karmaşıklık düzeyine sahip bir durum için oldukça karmaşıktır
Boris Callens

26

Aslında bunu çok kolay bir şekilde yapabilirsiniz. Aşağıdaki kodu kullanın.

enum GroupTypes
{
   OEM,
   CMB
};

Daha sonra her bir enum öğesinin dize değerini almak istediğinizde aşağıdaki kod satırını kullanın.

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

Geçmişte bu yöntemi başarıyla kullandım ve dize sabitlerini tutmak için bir sabitler sınıfı kullandım, her ikisi de oldukça iyi çalışıyor, ama bunu tercih etme eğilimindeyim.


Aynı şeyi düşünüyordum, ama bunu yakalamalıyım ... Aksi takdirde daha fazla insanın bunu önereceğinden şüphelenirim (Belki sadece paranoyakım).
Matthijs Wessels

Bunun farkında olduğum tek şey, dizeyi anlamak için yansıma kullandığına inanıyorum. Sonuç olarak, sabit bir dizeyi takip etmek için bir çözümden hemen sonrayım, genellikle sabit dizelerimin çoğunu saklamak için bir sınıf kullanacağım. Bununla birlikte, bir Enum'un (Enum öğelerim hakkında açıklayıcı bir dize almasına bakılmaksızın) doğru çözüm olduğu bir durumum varsa, yönetmek için bir yerde yüzen ekstra bir dize yerine, yalnızca enum değerini açıklandığı gibi kullanıyorum.
Arthur C

+1 Bu en iyi ve en kolay cevaptır ve burada kanıtlamak için yüksek oyları vardır . Uzantı modelini kullanmanın daha iyi olduğu tek zaman metinde boşluklara ihtiyaç duyduğunuz zamandır (daha fazla ayrıntı burada ).
SharpC

14
Hayır, bu sadece numara numarasının adını alıyor, numara numarasına dize atamıyor. OP'nin amacı enum değerinden farklı bir dizeye sahip olmaktır, örneğin: TheGroup = "OEM", TheOtherGroup = "CMB".
Tim Autin

3
Ben Tim'in comment @, bu fikirde değil OP yapmaya çalıştığı şey. Bunun kullanım durumunun ne olduğunu merak ediyorsanız, bir aygıtın dizeleri komut olarak aldığı bir durumu düşünün, ancak komutun "insan tarafından okunabilir" bir sürümü olması gerekir. Ben "UPDATEFW" komutu ile "Güncelleme Bellenim" gibi bir şey ilişkilendirmek için buna ihtiyacım vardı.
JYelton

20

Statik bir sınıfa sabitler eklemeyi deneyin. Sonunda bir Tür bulunmaz, ancak okunabilir, düzenli sabitleriniz olur:

public static class GroupTypes {

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

}

3
Koddan açıklayıcı ada geri dönmek zor. Bir eşleşme aramak için tüm sabit alanlar üzerinde yansıma kullanmanız gerekir.
andleer

1
@andleer Endişenizi anlamıyorum. Kullandığım çözüm bu.
VSO

Evet bu tam olarak istediğim şeydi. Ve bu gördüğüm en özlü / zarif çözüm, sanki int değerlerini w / int değerleriyle tanımlamışım gibi - bunun yerine dize değerleriyle. % 100 mükemmel.
Çad

3
Buradaki sorun, sonlu değerler listesiyle ayrı bir tipimiz olmayacağı için bir Enum olarak çalışmadığıdır. Bunları bekleyen bir fonksiyon, hataya eğilimli serbest biçimli dizelerle kullanılabilir.
Juan Martinez

14

DB'niz için aşağıdakileri içeren ikinci bir numaralandırma oluşturun:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

Artık "OEM" ve "CMB" karakter dizilerinden doğru DBGroupTypes değerini almak için Enum.Parse komutunu kullanabilirsiniz. Daha sonra bunları int'e dönüştürebilir ve modelinizde daha fazla kullanmak istediğiniz doğru numaralandırmadan doğru değerleri alabilirsiniz.


Bu süreçte ekstra bir adım gibi görünüyor, neden her şeyi işleyen bir sınıf olmasın?
C. Ross

11
Nitelikleri ve yansımayı kullanmanın aksine?
Dave Van den Eynde

13

Bir sınıf kullanın.

Düzenleme: Daha iyi örnek

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
Koddan açıklayıcı ada geri dönmek zor. Bir eşleşme aramak için tüm sabit alanlar üzerinde yansıma kullanmanız gerekir.
andleer

1
Senin değinmek istediğin noktayı anlıyorum. Daha sonra acutally çalışan bir sürüm yükleyeceğim, ancak oldukça ağır olduğunu itiraf ediyorum.
C. Ross

Benim versiyonum C. Ross'un çözümüne dayanan stackoverflow.com/a/48441114/3862615
Roman M

7

Sorunla başa çıkmanın başka bir yolu, bir enum ve enum değerlerini dize listesiyle eşleştirecek bir dizi dizeye sahip olmaktır:

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

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

böyle bir şey kullanabilirsiniz:

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

SPK isteyecektir

Artıları:

  1. Kolay ve temiz kod.
  2. Yüksek Performans (özellikle sınıfları kullanan yaklaşımlarla karşılaştırıldığında)

EKSİLERİ:

  1. Düzenlerken listeyi karıştırmaya eğilimlidir, ancak kısa bir liste için uygun olacaktır.

6

İşte enum değerini dize olarak almak için kullandığım uzantı yöntemi. İlk önce numaralandırma.

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

Description özniteliği System.ComponentModel'den geldi.

Ve işte benim uzantı yöntemim:

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

Şimdi, aşağıdaki kodu kullanarak numaralandırmaya dize değeri olarak erişebilirsiniz:

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}

5

Sözlük kullanarak bir arama tablosu düşündünüz mü?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

Daha sonra bir dize okurken aramak için GroupTypeLookup.TryGetValue () kullanabilirsiniz.


Belirli bir değerin anahtarını nasıl kolayca elde edersiniz?
eglasius

Soru başka yoldan gitmek istemedi. Ancak, diğer tarafa giden başka bir sözlük oluşturmak yeterince basit olurdu. Yani, Sözlük <GroupTypes, string>.
Jim Mischel

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 # numaralandırılmış dizeleri desteklemez, ancak çoğu durumda istenen efekti elde etmek için bir Liste veya Sözlük kullanabilirsiniz.

Başarılı / başarısız sonuçlarını yazdırmak için:

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

2

Ben bir sınıfa tamamen bir enum önlemek bir sınıf haline. Ve sonra bir yazı tipi işleyicinin kullanımı ile nesneyi db'den yakaladığınızda oluşturabilirsiniz.

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

Ben sadece bir sözlük oluşturmak ve kodu anahtar olarak kullanmak istiyorum.

Düzenleme: (Anahtar bulma) geriye doğru arama yapma hakkında yorum ele almak için, bu çok verimli olmaz. Bu gerekliyse, onunla başa çıkmak için yeni bir sınıf yazardım.


Ayrıca belirli bir değer için kolayca bir anahtar alabilir misiniz?
eglasius

C.Ross'a - Ne demek istediğinden emin değilim. Değerleri bir db'den okuyabilir ve sözlüğü dinamik olarak doldurabilirsiniz.
jhale

2

İlk sorum - Veritabanının kendisine erişiminiz var mı? Bu, veritabanında normalleştirilmelidir, ideal olarak, aksi takdirde, herhangi bir çözüm hataya eğilimli olacaktır. Deneyimlerime göre, "OEM" ve "SPK" ile dolu veri alanları, "oem" ve diğer "bok verileri" gibi şeylerin zamanla karışmasına neden olmaya eğilimlidir .... Bunu normalleştirebilirseniz, anahtarı kullanabilirsiniz. Enum'unuz olarak öğeleri içeren tabloda ve daha temiz bir yapıda işiniz bitti.

Bu uygun değilse, Enum'unuzu yapacağım ve dizenizi sizin için Enum'a ayrıştıracak bir sınıf yapacağım. Bu, en azından standart olmayan girişlerin işlenmesinde esneklik ve hataları yakalamak veya işlemek için Enum.Parse / Reflection / etc kullanarak geçici çözümlerden herhangi birini yapmaktan çok daha fazla esneklik sağlar. Bir sözlük işe yarayabilir, ancak vaka sorunlarınız vb. Varsa bozulabilir.

Yapabilmeniz için bir sınıf yazmanızı tavsiye ederim:

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

Bu, DB'yi değiştirmek zorunda kalmadan okunabilirliğinizin çoğunu korur.


2

Doğru anlıyorsam, dize enum için bir dönüşüm gerekir:

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

İsterseniz enum tipi için jenerik ilaçlarla daha süslü hale getirebilirsiniz.


2

VS 2015'te, nameof

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

Kullanımı:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

2

Glennular Extension yönteminde küçük bir değişiklik, böylece uzantıyı ENUM'dan başka şeylerde kullanabilirsiniz;

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

Veya Linq'i Kullanma

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 cevabını takiben biraz daha ileri gitmeye ve Jenerik yapmaya çalıştım, neredeyse orada görünüyorum ama bir vaka hala direniyor ve muhtemelen kodumu biraz basitleştirebilirim.
Herkes nasıl düzeltebilir ve özellikle bir dize atayamaz gibi çalışır hale görmek görmek buraya gönderirim

Şimdiye kadar aşağıdaki sonuçlara sahibim:

        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 .... :(:(

Büyülerin olduğu yer:

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



}

Bunu ancak enum'larım için beyan etmek zorundayım:

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

Bu harika iş için teşekkürler, uzun zamandır böyle bir yaklaşım arıyordum. Bunun için 1000 puan almanız gerektiğini düşünüyorum
user3492977

Oh bu yorum için teşekkür ederim, ve bu hatırlatmak için teşekkür ederim, ben bu kod biraz yazdığımda iki yıldır c # kullanmamıştı, ben yakında geri almak gerekir!
Lomithrani

@ user3492977 Sonunda geri döndüm ve tamamen işlevsel hale getirdim, harika bir fikir veya işe yaramaz bir şey olsa da hala şüpheliyim: D stackoverflow.com/questions/62043138/…
Lomithrani

2

Yeni de .Net Çekirdek 3.0 / C # 8.0 (Çalışma ortamınız Projenizi yükseltmek için izin verirse) kısa el switch deyimi olduğunu görünüyor biraz enum arası. Günün sonunda, yıllardır kullandığımız eski sıkıcı anahtar ifadesi.

Buradaki tek gerçek fark, switch ifadesinin yeni bir takım olması.

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

Buradan kopyaladığım kodun aslında bir enum'u bir param olarak kullandığını göreceksiniz .

Tam olarak ne istediğinizi değil (ve bana güvenin, OP'nin uzun zamandır talep ettiği şeye benzer bir şey istedim), ama aslında bunun bir parça MS'den bir zeytin dalı olduğunu hissediyorum. JMO.

Umarım birine yardım eder!


2

Önceki bir cevapta olduğu gibi bir yapı kullandım, ancak herhangi bir karmaşıklığı ortadan kaldırdım. Bana göre, bu en çok iplerin numaralandırılmasını oluşturmaktı. Bir numaralandırma ile aynı şekilde kullanılır.

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

Örnek kullanım:

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

1

@Even (via önerdiği gibi Hatta birkaç çeteleler uygulanan class Xve public static Xüyeleri) sadece bu gün, .Net 4.5 başlayarak var olduğunu sonradan öğrenmek için, sağ ToString() yöntemi.

Şimdi her şeyi tekrar numaralandırmaya uyguluyorum.


1

Bu, güçlü bir şekilde yazılmış bir parametre veya dize olarak kullanmanın bir yoludur :

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

İki numaralandırma kullanabilirsiniz. Biri veritabanı, diğeri okunabilirlik için.

Sadece senkronize kaldıklarından emin olmanız gerekir, bu da küçük bir maliyet gibi görünüyor. Değerleri ayarlamak zorunda değilsiniz, sadece konumları aynı şekilde ayarlayın, ancak değerlerin ayarlanması iki numaralandırmanın birbiriyle ilişkili olduğunu çok netleştirir ve hataların numaralandırma üyelerini yeniden düzenlemesini önler. Bir yorum, bakım ekibinin bunların ilgili olduğunu ve senkronize olarak tutulması gerektiğini bilmesini sağlar.

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}

// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

Kullanmak için önce koda dönüştürmeniz yeterlidir:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

Daha da kolay hale getirmek istiyorsanız, yalnızca bu tür numaralandırma için çalışan bir uzantı işlevi ekleyebilirsiniz:

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

ve sonra şunları yapabilirsiniz:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();

Bu kötü bir uygulamadır: Bağımlı enumolan biri ile amaçlanan değer değişikliği, yanlışlıkla diğerini mahvedebilir.
Lorenz Lo Sauer

1

Temelde @ArthurC'nin Yansıma cevabını arıyordum

Cevabını biraz genişletmek için, genel bir işleve sahip olarak daha da iyi hale getirebilirsiniz:

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

O zaman sahip olduğunuz her şeyi sarabilirsiniz

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

veya

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic

1

@EvenMien'den alındı ​​ve yorumların bazılarına eklendi. (Ayrıca kendi kullanım durumum için)

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

Bu sınıfı ekleme

public class DatabasePreference {
    public DatabasePreference([CallerMemberName] string preferenceName = "") {
        PreferenceName = preferenceName;
    }
    public string PreferenceName;
}

Bu çalışma CallerMemberNamekodlamayı en aza indirmek için kullanılıyor

Kullanımı:

//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();

Dene:

Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);

çıktı:

ScannerDefaultFlashLight
Scanner1dCodes

0

Diğer görüşlere dayanarak, ben bunu ortaya çıkardım. Bu yaklaşım, sabit değeri almak istediğiniz yere .Value yazmak zorunda kalmaz.

Bunun gibi tüm dize numaralandırmalar için bir temel sınıf var:

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 şöyle:

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

Ve gerçek bir dize sıralaması şu şekilde olacaktır:

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

Ve bununla birlikte, Value özelliğini kullanmadan json'a serileştirmek için Color.Red'i kullanabilirsiniz.


0

Dizeleri niteliklerde saklamak gibi sağlam bir şeye ihtiyacım yoktu. Sadece MyEnum.BillEveryWeek"her hafta fatura" ya MyEnum.UseLegacySystemda "eski sistemi kullan " gibi bir şey dönüştürmek gerekiyordu - temelde enum deve kasası ile bireysel küçük harfli kelime bölün.

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() "eski sistemi kullan" çıktıları

Birden fazla bayrak ayarladıysanız, bunu düz ingilizceye dönüştürür (son virgül yerine "ve" dışında virgülle ayrılmış).

var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes;

Console.WriteLine(myCustomerBehaviour.UnCamelCase());
//outputs "bill every week, use legacy system and charge taxes"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.