การเลือกค่าเริ่มต้นของประเภท Enum โดยไม่ต้องเปลี่ยนค่า


208

ใน C # เป็นไปได้ไหมที่จะตกแต่งประเภท Enum ด้วยคุณสมบัติหรือทำอย่างอื่นเพื่อระบุค่าเริ่มต้นที่ควรจะเป็นโดยไม่ต้องเปลี่ยนค่าหรือไม่ จำนวนที่ต้องการอาจถูกกำหนดด้วยเหตุผลใด ๆ ก็ตามและมันก็จะสะดวกในการควบคุมค่าเริ่มต้น

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

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

คุณควรจะสามารถเปลี่ยนค่าเริ่มต้นสำหรับ int หรือไม่? คู่? ฯลฯ ?
AR

2
@AR ไม่มีความผิดที่จะผ่านมาคุณ แต่ก็ไม่สมเหตุสมผลที่จะเปรียบเทียบ enums กับints ในนามธรรมเพียงเพราะมันเกิดขึ้นเพื่อนำไปใช้เป็นประเภทตัวเลข เราสามารถใช้ enums เป็นสตริงและมันจะไม่เปลี่ยนประโยชน์ของพวกเขา ฉันพิจารณาคำตอบที่นี่ข้อ จำกัด ของความหมายของภาษา C #; ข้อ จำกัด นั้นไม่ได้มีอยู่ในแนวคิดของ "การแยกค่าจากชุดที่ จำกัด "
jpaugh

1
@ jpaugh ฉันไม่ได้เปรียบเทียบ enums กับ ints "ในนามธรรม" ฉันให้ตัวอย่างของข้อมูลอื่น ๆ (รวมถึงสตริงและการอ้างอิงอื่น ๆ ) ประเภทที่เปลี่ยนค่าเริ่มต้นไม่สมเหตุสมผล มันไม่ได้เป็นข้อ จำกัด มันเป็นคุณสมบัติการออกแบบ สอดคล้องเป็นเพื่อนของคุณ :)
AR

@ จุดที่นำมา ฉันคิดว่าฉันใช้เวลามากเกินไปในการคิดว่าenums เป็นระดับโครงสร้างโดยเฉพาะเป็นประเภทรวม (หรือดูที่นี่นั่นคือพิจารณาแต่ละ enum เป็นประเภทที่แตกต่างกันซึ่งค่าทั้งหมดของประเภทนั้นแตกต่างจากค่าของ enum อื่น ๆ จากความคิดดังกล่าวเป็นไปไม่ได้ที่ enums จะแบ่งปันค่าใด ๆและแน่นอนสิ่งที่เป็นนามธรรมนี้แตกสลายเมื่อคุณพิจารณาว่าการเริ่มต้นของ0อาจหรืออาจไม่ถูกต้องสำหรับ enum ที่กำหนดและเป็นเพียงรองเท้าที่เขาแทงเข้าไปในทุก enum
jpaugh

ใช่ฉันคุ้นเคยกับสหภาพที่ถูกเลือกปฏิบัติ C # Enums ไม่ใช่แบบนั้นดังนั้นฉันไม่รู้ว่าจะเป็นประโยชน์ถ้าคิดในระดับสูง (และไม่ถูกต้อง) เช่นนั้นหรือไม่ ในขณะที่ 'ผลรวมประเภท' มีข้อได้เปรียบอย่างแน่นอนเช่นนั้นและ enum (สมมติว่ามีการจัดเตรียมค่าที่เหมาะสม) เช่น myColor = Colors.Red | Colors.Blue ประเด็นหลักของฉันคือถ้าคุณต้องการประเภทผลรวมสำหรับ c # ให้ทำแทนการพยายามกำหนดแนวคิดของ enum ใหม่
AR

คำตอบ:


349

ค่าเริ่มต้นสำหรับenum(ในความเป็นจริงชนิดของค่าใด ๆ ) คือ 0 - แม้ว่าจะไม่ใช่ค่าที่ถูกต้องสำหรับสิ่งenumนั้น มันไม่สามารถเปลี่ยนแปลงได้


13
ใช้ถ้อยคำใหม่คำถามที่จะถามว่าค่าเริ่มต้นสำหรับเป็น int เป็น 42. คิดว่าบ้าว่าเสียง ... หน่วยความจำคอมพ์โดยรันไทม์ก่อนที่คุณจะได้รับมัน enums มี structs จำ
ShuggyCoUk

3
@DougS 1. ไม่ แต่ยอมรับว่าคุณผิด 2. เขาไม่ได้รับชื่อเสียงจากความคิดเห็น upvotes
Aske B.

7
ความคิดเห็นทำให้ฉันสงสัยเกี่ยวกับคำตอบนี้ดังนั้นฉันทดสอบและตรวจสอบว่าคำตอบนี้ถูกต้องแน่นอน
Ian Newson

1
@JamesCurran แต่เมื่อไม่ได้ใช้ค่า 0 สำหรับ enums ฉันพบ "มีข้อยกเว้นประเภท 'System.NullReferenceException' เกิดขึ้นใน MyProjectName.dll แต่ไม่ได้จัดการในรหัสผู้ใช้ข้อมูลเพิ่มเติม: การอ้างอิงวัตถุไม่ได้ตั้งค่าเป็นอินสแตนซ์ของวัตถุ" ความผิดพลาด จะแก้ไขได้อย่างไร? หมายเหตุ: ฉันใช้วิธีการขยายเพื่อแสดงคำอธิบายของ enum แต่ไม่แน่ใจว่าจะหลีกเลี่ยงข้อผิดพลาดในวิธีผู้ช่วย (GetDescription) ที่กำหนดในหน้านี้ได้อย่างไร
Jack

64

ค่าเริ่มต้นของ enum ใด ๆ เป็นศูนย์ ดังนั้นหากคุณต้องการตั้งค่าตัวแจงนับหนึ่งให้เป็นค่าเริ่มต้นให้ตั้งค่านั้นเป็นศูนย์และตัวแจงนับอื่น ๆ ทั้งหมดเป็นศูนย์ (ตัวระบุแรกที่มีค่าเป็นศูนย์จะเป็นค่าเริ่มต้นสำหรับ enum นั้นหากมีหลายตัวนับ ด้วยค่าศูนย์)

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'

หากตัวแจงนับของคุณไม่ต้องการค่าที่ชัดเจนให้ตรวจสอบให้แน่ใจว่าตัวแจงนับตัวแรกคือตัวที่คุณต้องการให้เป็นตัวแจงนับเริ่มต้นตั้งแต่ "โดยค่าเริ่มต้นตัวแจงนับตัวแรกมีค่า 0 และค่าของตัวแจงนับต่อเนื่องเพิ่มขึ้น 1." ( การอ้างอิง C # )

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

Orientation o; // initialized to 'None'

38

หากศูนย์ไม่ทำงานเป็นค่าเริ่มต้นที่เหมาะสมคุณสามารถใช้โมเดลส่วนประกอบเพื่อกำหนดวิธีแก้ปัญหาสำหรับ enum:

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

จากนั้นคุณสามารถโทร:

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

หมายเหตุ: คุณจะต้องรวมบรรทัดต่อไปนี้ไว้ที่ด้านบนของไฟล์:

using System.ComponentModel;

สิ่งนี้ไม่เปลี่ยนค่าเริ่มต้นภาษา C # จริงของ enum แต่ให้วิธีการระบุ (และรับ) ค่าเริ่มต้นที่ต้องการ


ขออภัยมันไม่ได้ผลสำหรับคุณ คุณสามารถเพิ่มข้อมูลเพิ่มเติมได้ไหม? คุณต้องเพิ่มบรรทัดโดยใช้ System.ComponentModel; แล้วเขียนฟังก์ชัน GetDefaultEnum () ในคลาส Utilities คุณใช้. net เวอร์ชันใดอยู่
David

3
+1 สำหรับการนำองค์ประกอบแบบจำลององค์ประกอบและโซลูชันใหม่มาใช้ใหม่ ผมอยากจะแนะนำให้คุณเปลี่ยนบรรทัดสุดท้ายในคำสั่งดังต่อไปนี้:else return default(TEnum);กำปั้นมันจะลดการEnum.GetValues(...).***โทรช้าลงที่สอง (และที่สำคัญกว่า) มันจะเป็นเรื่องธรรมดาสำหรับประเภทใด ๆ แม้ไม่ใช่ enums นอกจากนี้คุณไม่ได้ จำกัด รหัสที่จะใช้สำหรับ enums เท่านั้นดังนั้นสิ่งนี้จะแก้ไขข้อยกเว้นที่เป็นไปได้จริงเมื่อใช้กับประเภทที่ไม่ใช่ enum
Ivaylo Slavov

1
นี่อาจเป็นการใช้ผิดวัตถุประสงค์ของแอตทริบิวต์ค่าเริ่มต้นในบริบทของคำถามที่ถาม คำถามที่ถามคือเกี่ยวกับค่าเริ่มต้นโดยอัตโนมัติซึ่งจะไม่เปลี่ยนแปลงกับโซลูชันที่เสนอ คุณลักษณะนี้มีไว้สำหรับค่าเริ่มต้นของนักออกแบบภาพที่แตกต่างจากค่าเริ่มต้น ไม่มีการพูดถึงโดยบุคคลที่ถามคำถามของนักออกแบบภาพ
David Burg

2
ไม่มีอะไรในเอกสารประกอบของ MSDN ที่ ComponentModel หรือ DefaultAttribute เป็นคุณสมบัติ "visual designer" เท่านั้น ในฐานะที่เป็นคำตอบที่ได้รับการยอมรับ คำตอบสั้น ๆ คือ "ไม่เป็นไปไม่ได้" ในการกำหนดค่าเริ่มต้นของ enum ให้กับสิ่งอื่นที่ไม่ใช่ค่า 0 คำตอบนี้เป็นวิธีแก้ปัญหา
David

17

ค่าเริ่มต้นของ enum คือค่าใด ๆ ที่เท่ากับศูนย์ ฉันไม่เชื่อว่าสิ่งนี้สามารถเปลี่ยนแปลงได้โดยคุณลักษณะหรือวิธีการอื่น

(MSDN พูดว่า: "ค่าเริ่มต้นของ enum E คือค่าที่สร้างโดยนิพจน์ (E) 0")


13
อย่างเคร่งครัดไม่จำเป็นต้องมีการแจงนับด้วยค่านี้ ศูนย์ยังคงเป็นค่าเริ่มต้น
Marc Gravell

11

คุณทำไม่ได้ แต่ถ้าคุณต้องการคุณสามารถทำบางอย่างได้ :)

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

การใช้งานของ struct นี้เป็น enum ง่าย
ที่คุณสามารถสร้าง pa == Orientation.East (หรือค่าใด ๆ ที่คุณต้องการ) โดยค่าเริ่มต้น
เพื่อใช้เคล็ดลับตัวเองคุณจะต้องแปลงจาก int โดยรหัส
มีการใช้งาน:

        #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

ในบริการของคุณนัยแปลงที่คุณต้องvalue + 1มิฉะนั้นตอนนี้คุณผลตอบแทนdefault(Orientation) Eastนอกจากนี้ทำให้ตัวสร้างเป็นส่วนตัว วิธีการที่ดี
nawfal

10

อีกวิธีหนึ่งที่อาจเป็นประโยชน์ - ใช้ "นามแฝง" บางประเภท ตัวอย่างเช่น:

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

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

1
ข้อเสนอแนะนั้นดีอย่างไรก็ตามตามที่ระบุไว้แล้วในคำตอบอื่น ๆ การแจกแจงมีค่าเริ่มต้นให้เป็นศูนย์ ในกรณีของคุณนิพจน์Status s = default(Status);จะไม่เป็นสมาชิกสถานะใด ๆ เนื่องจากsจะมีค่า(Staus) 0เป็น หลังถูกต้องในการเขียนโดยตรงเนื่องจาก enums สามารถแปลงเป็นจำนวนเต็มได้ แต่จะล้มเหลวในระหว่างการดีซีเรียลไลซ์เซชันเนื่องจากกรอบงานทำให้แน่ใจว่า enum จะถูกดีซีเรียลไลซ์ให้กับสมาชิกที่ถูกต้องเสมอ รหัสของคุณจะถูกต้องสมบูรณ์ถ้าคุณเปลี่ยนสายไปNew = 10 New = 0
Ivaylo Slavov

1
ใช่. ใหม่ = 0 ใช้งานได้ ฉันเองจะหลีกเลี่ยงไม่ได้ตั้งค่าสมาชิก enum อย่างชัดเจน
Dmitry Pavlov

7

จริงenumเริ่มต้น 's เป็นองค์ประกอบแรกในที่มีค่าenum0

ตัวอย่างเช่น:

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
อย่างไรก็ตามในกรณีนี้ "Pony" คือ "Cat" (เช่นConsole.WriteLine(Animals.Pony);พิมพ์ "Cat")
James Curran

16
ที่จริงแล้วคุณไม่ควรระบุ: ห้ามระบุค่าใด ๆ หรือระบุค่าทั้งหมดหรือระบุค่าของสมาชิกที่กำหนดครั้งแรกเท่านั้น นี่คือสิ่งที่เกิดขึ้นคือ: Cat ไม่มีค่าและเป็นค่าแรกดังนั้นตั้งค่าเป็น 0 โดยอัตโนมัติ Dog ไม่มีค่าตั้งค่าเป็น PreviousValue + 1 โดยอัตโนมัติคือ 1 Poney มีค่าปล่อยให้เป็นค่า ดังนั้น Cat = Pony = 0, Dog = 1. หากคุณมี {Cat, Dog, Pony = 0, Frog} ดังนั้น Dog = Frog = 1
user276648

4

The default value of enum is the enummember equal to 0 or the first element(if value is not specified) ... แต่ฉันต้องเผชิญกับปัญหาร้ายแรงโดยใช้ enum ในโครงการของฉันและเอาชนะด้วยการทำบางสิ่งบางอย่างด้านล่าง ... ความต้องการของฉันมีความสัมพันธ์กับระดับชั้นเรียน ...

    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
    }

และรับผลที่คาดหวัง

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

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

ทีนี้จะเกิดอะไรขึ้นถ้าค่ามาจาก DB .... ตกลงในสถานการณ์นี้ ... ผ่านค่าในด้านล่างฟังก์ชั่นและมันจะแปลงค่าเป็น enum ... ด้านล่างฟังก์ชั่นจัดการสถานการณ์ต่าง ๆ และเป็นเรื่องทั่วไป ... และเชื่อฉันว่า เร็วมาก ..... :)

    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 สำหรับเจตนาไม่ตอบคำถามที่ให้มา นี่ไม่ใช่ปัญหาการบ้านที่ชัดเจนซึ่งควรเป็นกรณีเดียวที่คุณไม่ได้ตั้งใจตอบ
Xynariz

1
@ Xynariz .. ขอโทษนะ .. ความคิดเห็นของฉันเป็นลบอย่างผิดพลาดเพราะความตั้งใจที่แท้จริงของฉันคือการแก้ปัญหาด้วยวิธีอื่น ... ดังนั้นฉันจึงเปลี่ยนความคิดเห็นของฉัน ... : D
Moumit

2

ค่าเริ่มต้นสำหรับประเภทการแจงนับคือ 0:

  • " โดยค่าเริ่มต้นตัวแจงนับตัวแรกมีค่า 0 และค่าของตัวแจงนับต่อเนื่องเพิ่มขึ้น 1 "

  • " ประเภทค่า enum มีค่าที่สร้างโดยนิพจน์ (E) 0 โดยที่ E คือตัวระบุ enum "

คุณสามารถตรวจสอบเอกสารสำหรับ C # enum ที่นี่และเอกสารสำหรับตาราง C # ค่าเริ่มต้นที่นี่


1

หากคุณกำหนด Default enum เป็น enum ด้วยค่าที่น้อยที่สุดคุณสามารถใช้สิ่งนี้:

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

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

firstEnum == Mine.

นี่ไม่ได้สันนิษฐานว่า enum มีค่าเป็นศูนย์


0

ค่าเริ่มต้นเป็นคนแรกในคำนิยาม ตัวอย่างเช่น:

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

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

สิ่งนี้จะกลับมา His


ฮ่า ๆ ; "ค่าเริ่มต้น" เป็นศูนย์ แต่! เขาบอกว่าค่าเริ่มต้น "ศูนย์" จะเกิดขึ้นเป็นสัญลักษณ์เริ่มต้นของค่าชื่อแรกเท่านั้น ! ดังนั้นในคำอื่น ๆ ภาษาเลือกค่าเริ่มต้นแทนคุณ; สิ่งนี้ก็เกิดขึ้นที่ศูนย์คือค่าเริ่มต้นของ int .. 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;
    }
}

หากคุณตั้งค่าคุณสมบัติเป็น null จะส่งคืนการวางแนวไม่มีเมื่อได้รับ _orientation คุณสมบัติเป็นโมฆะโดยค่าเริ่มต้น


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

จากนั้นในรหัสคุณสามารถใช้

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

14
/! \ WRONG /! \ ค่าเริ่มต้นค่าคุณสมบัติไม่ได้ตั้งค่าจริง ๆ มันเป็นเพียงเพื่อจุดประสงค์ในการให้ข้อมูลเท่านั้น จากนั้นก็ขึ้นอยู่กับคุณที่จะตรวจสอบว่า enum, field, property, ... ของคุณมีแอตทริบิวต์นั้นหรือไม่ PropertyGrid ใช้เพื่อให้คุณสามารถคลิกขวาและเลือก "รีเซ็ต" และหากคุณไม่ได้ใช้ค่าเริ่มต้นข้อความจะแสดงเป็นตัวหนา - แต่คุณยังต้องตั้งค่าคุณสมบัติของคุณเป็นค่าเริ่มต้นที่คุณต้องการด้วยตนเอง
276648
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.