Chọn giá trị mặc định của loại Enum mà không phải thay đổi giá trị


208

Trong C #, có thể trang trí một loại Enum bằng một thuộc tính hoặc làm một cái gì đó khác để chỉ định giá trị mặc định sẽ là gì, mà không phải thay đổi các giá trị? Các số bắt buộc có thể được đặt trong đá vì bất kỳ lý do gì và sẽ rất hữu ích khi vẫn có quyền kiểm soát mặc định.

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

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

Bạn có thể thay đổi giá trị mặc định cho int?, Double?, V.v.?
AR

2
@AR Không có ý xúc phạm đến bạn, nhưng sẽ không có ý nghĩa gì khi so sánh các enum với ints trong bản tóm tắt , đơn giản vì chúng tình cờ được thực hiện dưới dạng một kiểu số. Chúng ta có thể thực hiện enums dưới dạng chuỗi và nó sẽ không thay đổi tính hữu dụng của chúng. Tôi coi câu trả lời ở đây là giới hạn về tính biểu cảm của ngôn ngữ C #; giới hạn chắc chắn không phải là cố hữu trong ý tưởng "phân biệt các giá trị với một tập hợp hạn chế".
jpaugh

1
@jpaugh Tôi không so sánh enums với ints "trong bản tóm tắt". Tôi đang đưa ra các ví dụ về các loại dữ liệu khác (bao gồm các chuỗi và các tham chiếu khác) trong đó việc thay đổi mặc định là vô nghĩa. Đó không phải là một hạn chế, nó là một tính năng thiết kế. Kiên định là bạn của bạn :)
AR

@AR Điểm lấy. Tôi cho rằng tôi dành quá nhiều thời gian để nghĩ về enums như các cấu trúc mức loại, cụ thể là các loại tổng (hoặc xem ở đây . Nghĩa là, coi mỗi enum là một loại riêng biệt, trong đó tất cả các giá trị của loại đó là khác biệt với mọi giá trị của enum khác. Từ một suy nghĩ như vậy, enum không thể chia sẻ bất kỳ giá trị nào , và thực tế, sự trừu tượng này sẽ sụp đổ khi bạn cho rằng mặc định của 0may hoặc có thể không hợp lệ đối với một enum nhất định, và chỉ đơn giản là bị cắm sừng vào mỗi enum.
jpaugh

Vâng, tôi quen thuộc với các công đoàn bị phân biệt đối xử. C # Enums không phải vậy, vì vậy tôi không biết liệu có hữu ích khi nghĩ về chúng ở mức cao (và không chính xác) như vậy không. Mặc dù "loại tổng" chắc chắn có những ưu điểm của nó, và enum cũng vậy (giả sử các giá trị phù hợp được cung cấp). ví dụ: myColor = Colors.Red | Màu sắc. Màu sắc. Quan điểm chính của tôi là nếu bạn muốn một loại tổng cho c #, hãy tạo một loại, thay vì cố gắng tái sử dụng khái niệm enum.
AR

Câu trả lời:


349

Giá trị mặc định cho enum(trên thực tế, bất kỳ loại giá trị nào) là 0 - ngay cả khi đó không phải là giá trị hợp lệ cho điều đó enum. Nó không thể thay đổi.


13
Rephrase câu hỏi để hỏi rằng giá trị mặc định cho một int được 42. Nghĩ cách ngớ ngẩn mà âm thanh ... Bộ nhớ được blanked bởi bộ thực thi trước khi bạn nhận được nó, enums là struct nhớ
ShuggyCoUk

3
@DougS 1. Không, nhưng thừa nhận bạn đã sai là. 2. Anh ấy đã không kiếm được bất kỳ danh tiếng từ upvotes bình luận.
Aske B.

7
Các ý kiến ​​khiến tôi nghi ngờ về câu trả lời này, vì vậy tôi đã kiểm tra và xác minh rằng câu trả lời này chắc chắn là đúng.
Ian Newson

1
@JamesCurran Nhưng khi không sử dụng 0 giá trị cho enum tôi gặp phải "Một ngoại lệ của loại 'System.NullReferenceException' đã xảy ra trong MyProjectName.dll nhưng không được xử lý trong mã người dùng. Thông tin bổ sung: Tham chiếu đối tượng không được đặt thành phiên bản của đối tượng." lỗi. Làm thế nào để khắc phục nó? Lưu ý: Tôi sử dụng phương thức tiện ích mở rộng để hiển thị Mô tả của enum, nhưng không chắc chắn làm thế nào để tránh lỗi trong phương thức trợ giúp (GetDes mô tả) được xác định trên trang này
Jack

64

Giá trị mặc định của bất kỳ enum là 0. Vì vậy, nếu bạn muốn đặt một điều tra viên thành giá trị mặc định, thì hãy đặt giá trị đó thành 0 và tất cả các điều tra viên khác khác không (liệt kê đầu tiên có giá trị 0 sẽ là giá trị mặc định cho liệt kê đó nếu có nhiều liệt kê với giá trị bằng 0).

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'

Nếu các điều tra viên của bạn không cần các giá trị rõ ràng, thì hãy đảm bảo rằng điều tra viên đầu tiên là điều tra viên bạn muốn trở thành điều tra viên mặc định kể từ "Theo mặc định, điều tra viên đầu tiên có giá trị 0 và giá trị của mỗi điều tra viên kế tiếp được tăng lên 1. " ( Tham khảo C # )

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

Orientation o; // initialized to 'None'

38

Nếu zero không hoạt động như giá trị mặc định phù hợp, bạn có thể sử dụng mô hình thành phần để xác định cách giải quyết cho 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);
        }
    }
}

và sau đó bạn có thể gọi:

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

Lưu ý: bạn sẽ cần bao gồm dòng sau ở đầu tệp:

using System.ComponentModel;

Điều này không thay đổi giá trị mặc định của ngôn ngữ C # thực tế của enum, nhưng đưa ra một cách để chỉ ra (và nhận) giá trị mặc định mong muốn.


xin lỗi nó không làm việc cho bạn Bạn có thể thêm thông tin? bạn cần thêm dòng bằng System.ComponentModel; và sau đó viết hàm GetDefaultEnum () trong lớp Tiện ích. Bạn đang sử dụng phiên bản nào của .net?
David

3
+1 cho việc tái sử dụng thuộc tính mô hình thành phần và giải pháp sạch. Tôi muốn khuyên bạn nên thay đổi dòng cuối cùng trong elsetuyên bố như sau : return default(TEnum);. Nắm tay, nó sẽ làm giảm các Enum.GetValues(...).***cuộc gọi chậm hơn , thứ hai (và quan trọng hơn) nó sẽ chung cho bất kỳ loại nào, ngay cả không phải là enum. Ngoài ra, bạn không hạn chế mã chỉ được sử dụng cho enum, vì vậy điều này thực sự sẽ khắc phục các ngoại lệ tiềm ẩn khi được sử dụng trên các loại không phải là enum.
Ivaylo Slavov

1
Đây có thể là một sự lạm dụng của thuộc tính giá trị mặc định trong bối cảnh của câu hỏi được hỏi. Câu hỏi được hỏi là về giá trị khởi tạo tự động, sẽ không thay đổi với giải pháp được đề xuất. Thuộc tính này có nghĩa là mặc định của nhà thiết kế hình ảnh khác với giá trị ban đầu. Không có đề cập của người đặt câu hỏi của nhà thiết kế hình ảnh.
David Burg

2
Thực sự không có gì trong tài liệu MSDN rằng ElementModel hoặc DefaultAttribution chỉ là một tính năng "thiết kế trực quan". Như câu trả lời được chấp nhận. Câu trả lời ngắn gọn là "không, không thể" xác định lại giá trị mặc định của enum với giá trị khác với giá trị 0. Câu trả lời này là một cách giải quyết.
David

17

Một mặc định của enum là bất cứ điều gì liệt kê bằng không. Tôi không tin rằng điều này có thể thay đổi bởi thuộc tính hoặc phương tiện khác.

(MSDN nói: "Giá trị mặc định của enum E là giá trị được tạo bởi biểu thức (E) 0.")


13
Nghiêm túc, thậm chí không cần phải liệt kê với giá trị này. Zero vẫn là mặc định.
Marc Gravell

11

Bạn không thể, nhưng nếu bạn muốn, bạn có thể thực hiện một số mẹo. :)

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

sử dụng cấu trúc này như enum đơn giản.
nơi bạn có thể tạo pa == Orientation.East (hoặc bất kỳ giá trị nào bạn muốn) theo mặc định
để sử dụng thủ thuật, bạn cần chuyển đổi từ int theo mã.
có việc thực hiện:

        #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

Trong toán tử chuyển đổi ngầm định của bạn, bạn cần value + 1, nếu không bây giờ default(Orientation)trả lại của bạn East. Ngoài ra, làm cho các nhà xây dựng riêng tư. Cách tiếp cận tốt.
nawfal

10

Một cách nữa có thể hữu ích - sử dụng một số loại "bí danh". Ví dụ:

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

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

1
Tuy nhiên, gợi ý này là tốt, như đã đề cập trong các câu trả lời khác, các bảng liệt kê có giá trị mặc định là 0. Trong trường hợp của bạn, biểu thức Status s = default(Status);sẽ không là bất kỳ thành viên trạng thái nào, vì snó sẽ có giá trị (Staus) 0. Cái sau có giá trị để viết trực tiếp, vì enum có thể được chuyển thành số nguyên, nhưng nó sẽ thất bại trong quá trình khử lưu huỳnh, vì khung đảm bảo rằng một enum luôn được khử lưu cho thành viên hợp lệ. Mã của bạn sẽ hoàn toàn hợp lệ nếu bạn thay đổi dòng New = 10thành New = 0.
Ivaylo Slavov

1
Đúng. Mới = 0 sẽ hoạt động. Cá nhân tôi sẽ tránh không đặt thành viên enum một cách rõ ràng.
Dmitry Pavlov

7

Trên thực tế enum, mặc định là phần tử đầu tiên enumcó giá trị 0.

Ví dụ:

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
Tuy nhiên, trong trường hợp đó "Pony" IS "Cat" (ví dụ: Console.WriteLine(Animals.Pony);in "Cat")
James Curran

16
Trên thực tế, bạn nên: không bao giờ chỉ định bất kỳ giá trị HOẶC chỉ định tất cả các giá trị HOẶC chỉ chỉ định giá trị của thành viên được xác định đầu tiên. Ở đây điều xảy ra là: Cat không có giá trị và đó là giá trị thứ 1, do đó, tự động đặt nó thành 0. Dog không có giá trị, tự động đặt nó thành BeforeValue + 1 tức là 1. Poney có giá trị, để lại giá trị. Vậy Cat = Pony = 0, Dog = 1. Nếu bạn có {Cat, Dog, Pony = 0, Frog} thì 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) ... Nhưng tôi đã phải đối mặt với những vấn đề nghiêm trọng khi sử dụng enum trong các dự án của mình và khắc phục bằng cách làm điều gì đó bên dưới ... Bao giờ nhu cầu của tôi liên quan đến cấp lớp ...

    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
    }

và nhận được kết quả mong đợi

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

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

Bây giờ nếu giá trị đến từ DB .... Ok trong kịch bản này ... truyền giá trị trong hàm bên dưới và nó sẽ chuyển đổi giá trị thành enum ... bên dưới hàm xử lý các kịch bản khác nhau và nó chung chung ... và tin tôi là rất nhanh ..... :)

    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 vì cố ý không trả lời câu hỏi đã cho. Đây không phải là một vấn đề bài tập về nhà rõ ràng, đó là trường hợp duy nhất mà bạn cố tình không trả lời.
Xynariz

1
@Xynariz .. xin lỗi các bạn .. ý kiến ​​của tôi bị phủ nhận sai vì ý định thực sự của tôi là cung cấp giải pháp theo cách khác ... Vì vậy, tôi đã thay đổi nhận xét của mình ...: D
Moumit

2

Giá trị mặc định cho loại liệt kê là 0:

  • " Theo mặc định, điều tra viên đầu tiên có giá trị 0 và giá trị của mỗi điều tra viên kế tiếp được tăng thêm 1. "

  • " Enum loại giá trị có giá trị được tạo bởi biểu thức (E) 0, trong đó E là định danh enum. "

Bạn có thể kiểm tra tài liệu cho C # enum tại đây và tài liệu cho bảng giá trị mặc định của C # tại đây .


1

Nếu bạn xác định enum mặc định là enum có giá trị nhỏ nhất, bạn có thể sử dụng:

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

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

firstEnum == Mine.

Điều này không cho rằng enum có giá trị bằng không.


0

Mặc định là cái đầu tiên trong định nghĩa. Ví dụ:

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

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

Điều này sẽ trở lại His


haha; Giá trị mặc định là số không. NHƯNG! ông nói, giá trị mặc định "không" chỉ là ký hiệu mặc định của giá trị được đặt tên đầu tiên; ! vì vậy nói cách khác, ngôn ngữ chọn mặc định thay vì bạn; điều này cũng chỉ xảy ra rằng số 0 là giá trị mặc định của một 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;
    }
}

Nếu bạn đặt thuộc tính thành null sẽ trả về Định hướng. Không nhận được. Thuộc tính _orientation là null theo mặc định.


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

Sau đó, trong mã bạn có thể sử dụng

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

14
/! \ WRONG /! \ DefaultValueAttribution không thực sự đặt giá trị, nó chỉ dành cho mục đích thông tin. Sau đó, tùy thuộc vào bạn để kiểm tra xem enum, trường, thuộc tính, ... của bạn có thuộc tính đó không. PropertyGrid sử dụng nó để bạn có thể nhấp chuột phải và chọn "Đặt lại", nếu bạn không sử dụng giá trị mặc định, văn bản được in đậm - NHƯNG - bạn vẫn phải đặt thủ công tài sản của mình thành giá trị mặc định bạn muốn.
dùng276648
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.