값을 변경하지 않고 Enum 유형의 기본값 선택


208

C #에서 Enum 유형을 속성으로 장식하거나 값을 변경하지 않고 기본값을 지정하기 위해 다른 작업을 수행 할 수 있습니까? 필요한 숫자는 어떤 이유로 든 석재로 설정 될 수 있으며 여전히 기본값을 제어하는 ​​것이 편리합니다.

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

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

int ?, double? 등의 기본값을 변경할 수 있습니까?
AR

2
@AR 과거에 대한 공격은 없지만, 열거 형을 ints 비교하는 것은 의미가 없습니다 . 단순히 숫자 유형으로 구현되기 때문입니다. 열거 형을 문자열로 구현할 수 있으며 유용성을 변경하지는 않습니다. 나는 여기서의 대답이 C # 언어 표현의 한계라고 생각한다. 제한은 "제한된 세트와 값을 구별하는"아이디어에 내재되어 있지 않습니다.
jpaugh

1
@jpaugh 나는 열거 형을 int와 추상적으로 비교하지 않습니다. 기본값을 변경하는 것이 의미가없는 다른 데이터 (문자열 및 기타 참조 포함) 유형의 예를 제공합니다. 제한이 아니라 디자인 기능입니다. 일관성은 당신의 친구입니다 :)
AR

@AR 포인트 촬영. 나는 enum타입 레벨 구조, 특히 합계 유형 으로 s를 생각하는 데 너무 많은 시간을 소비한다고 가정 합니다 (또는 여기를 참조하십시오 . 즉, 각 열거 형을 고유 한 유형으로 간주 하십시오 . 즉, 해당 유형의 모든 값이 다른 모든 열거 형 값과 구별됩니다. 이러한 사고 방식에서 열거 형이 값 을 공유 하는 것은 불가능 하며 실제로이 추상화 0는 주어진 열거 형에 대한 기본값 이 유효하거나 유효하지 않을 수 있으며 모든 열거 형에 구두 혼입되어 있다고 생각하면 구분됩니다 .
jpaugh

예, 저는 차별적 인 노조에 익숙합니다. C # 열거 형은 그렇지 않으므로 그렇게 높은 (그리고 잘못된) 수준으로 생각하는 것이 도움이되는지 모르겠습니다. 'sum type'은 확실히 장점이 있지만 enum과 enum도 있습니다 (적절한 값이 제공된다고 가정). 예 : myColor = Colors.Red | 색상. 파란색. 내 주요 요점은 c #에 대한 합계 유형을 원한다면 열거 형 개념의 용도를 바꾸지 않고 하나를 만드십시오.
AR

답변:


349

enum(실제로 모든 값 유형) 의 기본값 은 0입니다 enum. 해당 값이 유효하지 않은 경우에도 마찬가지입니다 . 변경할 수 없습니다.


13
int의 기본값은 42가되도록 질문을 바꾸십시오. 그 소리가 어떻게 들리는 지 생각해보십시오. 메모리는 런타임에 비워 지고, 열거 형은 구조체를 기억합니다
ShuggyCoUk

3
@DougS 1. 아니요,하지만 당신이 틀렸다는 것을 인정하는 것입니다. 2. 그는 의견 공의로 명성을 얻지 못했다.
Aske B.

7
의견은이 답변에 대해 의심스럽게 만들었으므로 테스트 하고이 답변이 확실히 맞는지 확인했습니다.
Ian Newson

1
@JamesCurran 그러나 열거 형에 0 값을 사용하지 않으면 "MyProjectName.dll에서 'System.NullReferenceException'유형의 예외가 발생했지만 사용자 코드에서 처리되지 않았습니다. 추가 정보 : 개체 참조가 개체의 인스턴스로 설정되지 않았습니다." 오류. 고치는 방법? 참고 : 열거 형 설명을 표시하기 위해 확장 방법을 사용하지만 이 페이지에
Jack

64

열거 형의 기본값은 0입니다. 따라서 하나의 열거자를 기본값으로 설정하려면 해당 열거자를 0으로 설정하고 다른 모든 열거자를 0이 아닌 값으로 설정하십시오 (여러 열거자가있는 경우 값이 0 인 첫 번째 열거자가 해당 열거의 기본값이 됨). 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'

열거 자에 명시적인 값이 필요하지 않은 경우 "기본적으로 첫 번째 열거자는 0 값을 가지며 각 연속 열거 자의 값은 다음과 같이 증가하므로 첫 번째 열거자는 기본 열거자가 될 것이어야합니다. 1." ( C # 참조 )

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

Orientation o; // initialized to 'None'

38

0이 올바른 기본값으로 작동하지 않으면 구성 요소 모델을 사용하여 열거 형에 대한 해결 방법을 정의 할 수 있습니다.

[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 # 언어 기본값을 변경하지 않지만 원하는 기본값을 표시하고 얻는 방법을 제공합니다.


죄송합니다. 작동하지 않습니다. 더 많은 정보를 추가 할 수 있습니까? System.ComponentModel을 사용하여 행을 추가해야합니다. 그런 다음 유틸리티 클래스에서 GetDefaultEnum () 함수를 작성하십시오. 사용중인 .net 버전은 무엇입니까?
David

3
컴포넌트 모델 속성 및 클린 솔루션의 재사용에 +1 else명세서 의 마지막 줄 을 다음과 같이 변경하는 것이 좋습니다 return default(TEnum);. 주먹, 그것은 느린 Enum.GetValues(...).***호출 을 줄이며 , 두 번째 (더 중요한 것)는 열거 형이 아닌 모든 유형에 일반적입니다. 또한 열거 형에만 사용되는 코드를 제한하지 않으므로 열거 형 이외의 유형을 사용할 때 실제로 예외가 해결됩니다.
Ivaylo Slavov

1
이것은 질문의 맥락에서 기본값 속성의 오용일 수 있습니다. 질문은 자동으로 초기화 된 값에 관한 것이며 제안 된 솔루션으로 변경되지 않습니다. 이 속성은 비주얼 디자이너의 기본값이 초기 값과 다른 경우에 사용됩니다. 비주얼 디자이너의 질문을하는 사람은 언급하지 않습니다.
David Burg

2
MSDN 설명서에는 ComponentModel 또는 DefaultAttribute가 "시각적 디자이너"전용 기능이라는 것이 없습니다. 받아 들여진 대답은 다음과 같습니다. 짧은 대답은 열거 형의 기본값을 0 값 이외의 다른 값으로 다시 정의하는 "아니오, 불가능"입니다. 이 답변은 해결 방법입니다.
David

17

열거의 기본값은 열거가 0에 해당하는 것입니다. 나는 이것이 속성이나 다른 방법으로 변경 될 수 있다고 생각하지 않습니다.

(MSDN의 말 : "열거 E의 기본값은 식 (E) 0에 의해 생성 된 값입니다.")


13
엄밀히 말하면이 값으로 열거 할 필요조차 없습니다. 여전히 기본값은 0입니다.
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;
    }

이 구조체를 간단한 열거 형으로 사용합니다. 트릭 자체를 사용하기 위해
기본적
으로 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
그러나 다른 답변에서 이미 언급했듯이 열거 형의 기본값은 0입니다. 귀하의 경우 표현식 의 값은이므로 Status s = default(Status);상태 멤버가 아닙니다 . 후자는 열거 형을 정수로 캐스트 할 수 있으므로 직접 작성하는 것이 유효하지만 프레임 워크는 열거 형이 항상 유효한 멤버로 직렬화 해제되도록하기 때문에 직렬화 해제 중에 실패합니다. 행 을로 변경하면 코드가 완벽하게 유효합니다 . s(Staus) 0New = 10New = 0
Ivaylo Slavov

1
예. New = 0이 작동합니다. 나는 열거 형 멤버를 명시 적으로 설정하지 않는 것을 개인적으로 피할 것입니다.
Dmitry Pavlov

7

실제로 enum의 기본값은 enum값 의 첫 번째 요소 입니다.0 .

예를 들어 :

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
그러나,이 경우에 "포니", "고양이"(예를 들어, IS Console.WriteLine(Animals.Pony);인쇄 "고양이")
제임스 쿠란

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) ...하지만 프로젝트에서 열거 형을 사용하여 중요한 문제에 직면했으며 아래에서 무언가를 수행하여 극복했습니다 ... 내 요구가 수업 수준과 어떻게 관련되어 있는지 ...

    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에서 오는 경우 ....이 시나리오에서 좋아요 ... 아래 함수에서 값을 전달하면 값이 열거 형으로 변환됩니다 ... 아래 함수는 다양한 시나리오를 처리하고 일반적입니다 ... 매우 빠른 ..... :)

    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는 열거 형 식별자입니다. "

당신은 C #을 열거에 대한 문서를 확인하실 수 있습니다 여기에 , 그리고 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.

열거 형의 값이 0이라고 가정하지 않습니다.


0

기본값은 정의에서 첫 번째입니다. 예를 들면 다음과 같습니다.

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

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

이것은 돌아올 것이다 His


ㅋ; "default value"는 0입니다. 그러나! 그는 기본값 "zero"는 첫 번째 명명 된 값의 기본 기호 일 뿐이라고 말한다. ! 다시 말해 언어는 당신 대신에 기본값을 선택합니다. 이것은 또한 0이 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로 설정하면 Orientations.None이 반환됩니다. _orientation 속성은 기본적으로 null입니다.


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

그런 다음 코드에서 사용할 수 있습니다

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

14
/! \ WRONG /! \ DefaultValueAttribute는 실제로 값을 설정하지 않으며 단지 정보 목적으로 만 사용됩니다. 그런 다음 열거 형, 필드, 속성, ...에 해당 속성이 있는지 확인하는 것은 사용자의 몫입니다. PropertyGrid는이를 사용하여 마우스 오른쪽 버튼을 클릭하고 "재설정"을 선택할 수 있습니다. 또한 기본값을 사용하지 않는 경우 텍스트는 굵게 표시됩니다. 그러나 여전히 수동으로 속성을 원하는 기본값으로 설정해야합니다.
user276648
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.