Değerleri değiştirmek zorunda kalmadan bir Enum türünün varsayılan değerini seçme


208

C # 'da, bir Enum türünü bir öznitelikle dekore etmek veya değerleri değiştirmeden varsayılan değerin ne olacağını belirtmek için başka bir şey yapmak mümkün mü? Gerekli sayılar her ne sebeple olursa olsun taş haline getirilebilir ve varsayılan değer üzerinde hala kontrol sahibi olmak kullanışlı olacaktır.

enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Orientation o; // Is 'North' by default.

İnt ?, double ?, vb. İçin varsayılan değeri değiştirebilmeli misiniz?
AR

2
Size geçmiş için @AR Darılma ama hissinin Çeteleler karşılaştırmak yapmaz ints soyut içinde bir sayısal türleri olarak uygulanacak gerçekleşmesi çünkü. Sekmeleri dize olarak uygulayabiliriz ve yararlılıklarını değiştirmez. Burada cevabı C # dilinin ifade edilebilirliğinin bir sınırlaması olarak görüyorum; sınırlama kesinlikle "değerleri kısıtlı bir kümeden ayırma" fikrinin doğasında yoktur.
jpaugh

1
@jpaugh Enumları "soyutta" ints ile karşılaştırmıyorum. Varsayılanları değiştirmenin bir anlamı olmadığı diğer veri türlerini (dizeler ve diğer referanslar dahil) örnekler veriyorum. Bu bir sınırlama değil, bir tasarım özelliğidir. Tutarlılık arkadaşın :)
AR

@AR Alınan nokta. Bence enums'yi tip seviyesi yapılar olarak düşünmek için çok fazla zaman harcadığımı , özellikle de toplam türleri olarak (veya buraya bakın . Yani, her bir numaralandırmayı, bu türdeki tüm değerlerin diğer numaraların değerlerinden farklı olduğu ayrı bir tür olarak düşünün. Böyle bir zihniyetten, numaralandırmaların herhangi bir değeri paylaşması imkansızdır ve gerçekten de bu soyutlama 0, belirli bir numaralandırma için varsayılanın geçerli olabileceğini veya olmayabileceğini düşündüğünüzde ve her numarada ayakkabı boynuzlu olduğunu düştüğünüzde ayrılır .
jpaugh

Evet, ayrımcı sendikalara aşinayım. C # Enums bu değil, bu yüzden onları böyle yüksek (ve yanlış) düzeyde düşünmek yararlı olup olmadığını bilmiyorum. Bir 'toplam türü' kesinlikle avantajlarına sahip olsa da, ve numaralandırır (uygun değerlerin sağlandığı varsayılarak). örn. myColor = Renkler.Red | Colors.Blue. Benim asıl mesele, c # için bir toplam türü istiyorsanız, bir enum kavramını yeniden amaçlamak yerine bir tane yapın.
AR

Yanıtlar:


349

Bunun için enumgeçerli bir değer olmasa bile (aslında, herhangi bir değer türü) için varsayılan 0'dır enum. Değiştirilemez.


13
Bir int için varsayılan değerin 42 olmasını sormak için soruyu yeniden silin. Kulağa ne kadar daft geldiğini düşünün ... Bellek, çalışmadan önce çalışma zamanı tarafından boşaltılır , numaralandırmalar hatırlar
ShuggyCoUk

3
@ DooS 1. Hayır, ama yanıldığını itiraf etmek. 2. Yorum upvotes üzerinden herhangi bir ün kazanmadı.
Aske B.Kas

7
Yorumlar bu cevap hakkında beni şüpheli yaptı, bu yüzden test ettim ve bu cevabın kesinlikle doğru olduğunu doğruladım.
Ian Newson

1
@JamesCurran Ancak numaralandırmalar için 0 değerleri kullanılmadığında "MyProjectName.dll türünde 'System.NullReferenceException' türünde bir istisna oluştu, ancak kullanıcı kodunda işlenmedi. hata. Nasıl düzeltilir? Not: Enum'un Açıklamalarını görüntülemek için bir uzantı yöntemi kullanıyorum, ancak bu sayfada
Jack

64

Herhangi bir numaralandırmanın varsayılan değeri sıfırdır. Dolayısıyla, bir numaralandırıcıyı varsayılan değer olarak ayarlamak istiyorsanız, bunu sıfır olarak ve diğer tüm numaralandırıcıları sıfırdan farklı olarak ayarlayın (sıfır değerine sahip ilk numaralandırıcı, birden fazla numaralandırıcı varsa, bu numaralandırma için varsayılan değer olacaktır sıfır değeri ile).

enum Orientation
{
    None = 0, //default value since it has the value '0'
    North = 1,
    East = 2,
    South = 3,
    West = 4
}

Orientation o; // initialized to 'None'

Numaralandırıcılarınızın açık değerlere ihtiyacı yoksa, ilk numaralandırıcının varsayılan numaralandırıcı olmasını istediğiniz değer olduğundan emin olun, çünkü "Varsayılan olarak, ilk numaralandırıcının değeri 0'dır ve birbirini izleyen her numaralandırıcının değeri, 1." ( C # referansı )

enum Orientation
{
    None, //default value since it is the first enumerator
    North,
    East,
    South,
    West
}

Orientation o; // initialized to 'None'

38

Sıfır uygun varsayılan değer olarak çalışmazsa, numaralandırma için bir geçici çözüm tanımlamak üzere bileşen modelini kullanabilirsiniz:

[DefaultValue(None)]
public enum Orientation
{
     None = -1,
     North = 0,
     East = 1,
     South = 2,
     West = 3
 }

public static class Utilities
{
    public static TEnum GetDefaultValue<TEnum>() where TEnum : struct
    {
        Type t = typeof(TEnum);
        DefaultValueAttribute[] attributes = (DefaultValueAttribute[])t.GetCustomAttributes(typeof(DefaultValueAttribute), false);
        if (attributes != null &&
            attributes.Length > 0)
        {
            return (TEnum)attributes[0].Value;
        }
        else
        {
            return default(TEnum);
        }
    }
}

ve sonra şunları arayabilirsiniz:

Orientation o = Utilities.GetDefaultValue<Orientation>();
System.Diagnostics.Debug.Print(o.ToString());

Not: Dosyanın üstüne aşağıdaki satırı eklemeniz gerekir:

using System.ComponentModel;

Bu, numaralandırmanın gerçek C # dili varsayılan değerini değiştirmez, ancak istenen varsayılan değeri belirtmek (ve almak) için bir yol sağlar.


üzgünüm senin için işe yaramıyor. Daha fazla bilgi ekleyebilir misiniz? System.ComponentModel kullanarak satır eklemeniz gerekir; ve sonra bir Utilities sınıfına GetDefaultEnum () işlevini yazın. Hangi .net sürümünü kullanıyorsunuz?
David

3
Bileşen modeli özelliğinin ve temiz çözümün yeniden kullanımı için +1. Ben de son satırı değiştirmek tavsiye etmek isteriz elseşöyle açıklamada: return default(TEnum);. Yumruk, yavaş Enum.GetValues(...).***çağrıları azaltacaktır , ikincisi (ve daha önemlisi), her tür, hatta numarasızlar için genel olacaktır. Ayrıca, yalnızca numaralandırmalar için kullanılacak kodu kısıtlamazsınız, bu nedenle numarasız türlerde kullanıldığında potansiyel istisnaları düzeltir.
Ivaylo Slavov

1
Bu, sorulan soru bağlamında varsayılan değer özelliğinin yanlış kullanımı olabilir. Sorulan soru, önerilen çözümle değişmeyecek olan otomatik olarak başlatılan değerle ilgilidir. Bu özellik, görsel bir tasarımcının başlangıç ​​değerinden farklı olan varsayılan değeri içindir. Görsel tasarımcı sorusunu soran kişinin hiçbir sözü yoktur.
David Burg

2
MSDN belgelerinde ComponentModel veya DefaultAttribute'ın "görsel tasarımcı" yalnızca bir özellik olduğu konusunda hiçbir şey yoktur. Kabul edilen cevap belirttiği gibi. Kısa yanıt, bir numaralandırmanın varsayılan değerini 0 değerinden başka bir şeye yeniden tanımlamak "hayır, imkansız" dır. Bu cevap bir çözümdür.
David

17

Bir numaralandırma varsayılan numaralandırma sıfıra eşit olan şeydir. Bunun nitelik veya başka yollarla değiştirilebileceğine inanmıyorum.

(MSDN diyor ki: "Bir numaralandırma E'nin varsayılan değeri, (E) 0 ifadesi tarafından üretilen değerdir.")


13
Kesinlikle, bu değerle bir numaralandırmaya bile gerek yoktur. Sıfır hala varsayılan değerdir.
Marc Gravell

11

Yapamazsınız, ama isterseniz biraz hile yapabilirsiniz. :)

    public struct Orientation
    {
        ...
        public static Orientation None = -1;
        public static Orientation North = 0;
        public static Orientation East = 1;
        public static Orientation South = 2;
        public static Orientation West = 3;
    }

bu yapının basit enum olarak kullanılması.
Burada
, hilenin kendisini kullanmak için varsayılan olarak pa == Orientation.East (veya istediğiniz herhangi bir değeri) oluşturabilirsiniz , int'ten kodla dönüştürmeniz gerekir.
orada uygulama:

        #region ConvertingToEnum
        private int val;
        static Dictionary<int, string> dict = null;

        public Orientation(int val)
        {
            this.val = val;
        }

        public static implicit operator Orientation(int value)
        {
            return new Orientation(value - 1);
        }

        public static bool operator ==(Orientation a, Orientation b)
        {
            return a.val == b.val;
        }

        public static bool operator !=(Orientation a, Orientation b)
        {
            return a.val != b.val;
        }

        public override string ToString()
        {
            if (dict == null)
                InitializeDict();
            if (dict.ContainsKey(val))
                return dict[val];
            return val.ToString();
        }

        private void InitializeDict()
        {
            dict = new Dictionary<int, string>();
            foreach (var fields in GetType().GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                dict.Add(((Orientation)fields.GetValue(null)).val, fields.Name);
            }
        } 
        #endregion

Örtük dönüşüm operatörünüzde ihtiyacınız var value + 1, aksi takdirde şimdi default(Orientation)geri dönüşleriniz East. Ayrıca, yapıcıyı özel yapın. Iyi bir yaklaşım.
nawfal

10

Yararlı olabilecek bir yol daha - bir çeşit "takma ad" kullanmak. Örneğin:

public enum Status
{
    New = 10,
    Old = 20,
    Actual = 30,

    // Use Status.Default to specify default status in your code. 
    Default = New 
}

1
Öneri iyidir, ancak diğer cevaplarda da belirtildiği gibi, numaralandırmaların varsayılan değerleri sıfırdır. Sizin durumunuzda, ifadenin değerine sahip olacağı Status s = default(Status);için durum üyelerinden herhangi biri solmayacaktır (Staus) 0. İkincisi tamsayılara yayınlanabileceğinden, doğrudan yazmak için geçerlidir, ancak çerçeve bir enumun her zaman geçerli bir üyeye serileştirilmesini sağladığından, serileştirme sırasında başarısız olacaktır. Satırı New = 10olarak değiştirirseniz kodunuz tamamen geçerli olacaktır New = 0.
Ivaylo Slavov

1
Evet. Yeni = 0 işe yarar. Şahsen enum üyelerini açıkça ayarlamamaktan kaçınırım.
Dmitry Pavlov

7

Aslında bir enum'varsayılan'enum değeri, değeri olan0 .

Yani mesela:

public enum Animals
{
    Cat,
    Dog,
    Pony = 0,
}
//its value will actually be Cat not Pony unless you assign a non zero value to Cat.
Animals animal;

9
Ancak, bu durumda "Midilli" IS "Kedi" (örneğin, Console.WriteLine(Animals.Pony);"Kedi" yazdırır)
James Curran

16
Aslında şunlardan birini yapmalısınız: asla herhangi bir değer belirtmeyin VEYA tüm değerleri belirtin VEYA yalnızca ilk tanımlı üyenin değerini belirtin. İşte olur: Kedi hiçbir değeri yoktur ve bu 1. değerdir, bu yüzden otomatik olarak 0'a ayarlar. Köpek hiçbir değeri yoktur, otomatik olarak ÖncekiDeğer + 1'e ayarlar, yani 1. Poney'nin bir değeri vardır, değeri bırakın. Yani Kedi = Midilli = 0, Köpek = 1. {Kedi, Köpek, Midilli = 0, Kurbağa} varsa, Köpek = Kurbağa = 1.
user276648 14:30

4

The default value of enum is the enummember equal to 0 or the first element(if value is not specified) ... Ama projelerimde enum kullanımında kritik sorunlarla karşılaştım ve aşağıda bir şeyler yaparak üstesinden geldim ... İhtiyacımın sınıf düzeyiyle ne kadar alakalı olduğu ...

    class CDDtype
    {
        public int Id { get; set; }
        public DDType DDType { get; set; }

        public CDDtype()
        {
            DDType = DDType.None;
        }
    }    


    [DefaultValue(None)]
    public enum DDType
    {       
        None = -1,       
        ON = 0,       
        FC = 1,       
        NC = 2,       
        CC = 3
    }

ve beklenen sonucu al

    CDDtype d1= new CDDtype();
    CDDtype d2 = new CDDtype { Id = 50 };

    Console.Write(d1.DDType);//None
    Console.Write(d2.DDType);//None

Şimdi değer DB geliyorsa .... Tamam bu senaryoda ... değer aşağıdaki fonksiyonda geçmek ve değer enum dönüştürecek ... aşağıda fonksiyon çeşitli senaryo ele ve genel ... ve inan bana öyle çok hızlı ..... :)

    public static T ToEnum<T>(this object value)
    {
        //Checking value is null or DBNull
        if (!value.IsNull())
        {
            return (T)Enum.Parse(typeof(T), value.ToStringX());
        }

        //Returanable object
        object ValueToReturn = null;

        //First checking whether any 'DefaultValueAttribute' is present or not
        var DefaultAtt = (from a in typeof(T).CustomAttributes
                          where a.AttributeType == typeof(DefaultValueAttribute)
                          select a).FirstOrNull();

        //If DefaultAttributeValue is present
        if ((!DefaultAtt.IsNull()) && (DefaultAtt.ConstructorArguments.Count == 1))
        {
            ValueToReturn = DefaultAtt.ConstructorArguments[0].Value;
        }

        //If still no value found
        if (ValueToReturn.IsNull())
        {
            //Trying to get the very first property of that enum
            Array Values = Enum.GetValues(typeof(T));

            //getting very first member of this enum
            if (Values.Length > 0)
            {
                ValueToReturn = Values.GetValue(0);
            }
        }

        //If any result found
        if (!ValueToReturn.IsNull())
        {
            return (T)Enum.Parse(typeof(T), ValueToReturn.ToStringX());
        }

        return default(T);
    }

-1 verilen soruya kasten cevap vermemek için. Bu bariz bir ödev problemi değildir, kasıtlı olarak cevap vermemeniz gereken tek durum bu olmalıdır.
Xynariz

1
@Xynariz .. üzgünüm çocuklar .. yorumlarım yanlış bir şekilde negatifti çünkü gerçek niyetim başka bir şekilde çözüm sağlamaktı ... Bu yüzden yorumlarımı değiştirdim ...: D
Moumit

2

Numaralandırma türü için varsayılan değer 0'dır:

  • " Varsayılan olarak, ilk numaralandırıcı 0 değerine sahiptir ve her ardışık numaralandırıcının değeri 1 artırılır. "

  • " Enum değer türü, (E) 0 ifadesi tarafından üretilen değere sahiptir; burada E, enum tanımlayıcısıdır. "

Sen C # enum belgelerine kontrol edebilirsiniz burada , ve C # varsayılan değerler tablosu için dokümantasyon burada .


1

Default enum değerini en küçük değere sahip enum olarak tanımlarsanız, bunu kullanabilirsiniz:

public enum MyEnum { His = -1, Hers = -2, Mine = -4, Theirs = -3 }

var firstEnum = ((MyEnum[])Enum.GetValues(typeof(MyEnum)))[0];

firstEnum == Mine.

Bu, enum'un sıfır değere sahip olduğunu varsaymaz.


0

Varsayılan, tanımdaki ilk değerdir. Örneğin:

public enum MyEnum{His,Hers,Mine,Theirs}

Enum.GetValues(typeOf(MyEnum)).GetValue(0);

Bu geri dönecek His


haha; Varsayılan değer sıfırdır. FAKAT! "sıfır" varsayılan değerinin yalnızca ilk adlandırılan değerin varsayılan sembolü olduğunu söylüyor; ! başka bir deyişle, dil sizin yerine varsayılanı seçer; Bu da sadece sıfır bir int varsayılan değer olur .. lol
user1953264

0
enum Orientations
{
    None, North, East, South, West
}
private Orientations? _orientation { get; set; }

public Orientations? Orientation
{
    get
    {
        return _orientation ?? Orientations.None;
    }
    set
    {
        _orientation = value;
    }
}

Özelliği null olarak ayarlarsanız Yönlendirmeler döndürülür. _Orientation özelliği varsayılan olarak boştur.


-5
[DefaultValue(None)]
public enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Sonra kodda kullanabilirsiniz

public Orientation GetDefaultOrientation()
{
   return default(Orientation);
} 

14
/! \ WRONG /! \ DefaultValueAttribute gerçekten değeri ayarlamaz, sadece bilgi amaçlıdır. Ardından, sıralamanızın, alanınızın, mülkünüzün ... bu özelliğe sahip olup olmadığını kontrol etmek size kalmıştır. PropertyGrid bunu sağ tıklayıp "Sıfırla" yı seçebilmeniz için kullanır, ayrıca varsayılan değeri kullanmıyorsanız, metin kalın olarak gösterilir - AMA - yine de mülkünüzü manuel olarak istediğiniz varsayılan değere ayarlamanız gerekir.
user276648
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.