Microsoft MVP성태의 닷넷 이야기
enum 원소값이 중복인 경우 출력 [링크 복사], [링크+제목 복사],
조회: 13076
글쓴 사람
농상
홈페이지
첨부 파일
 

enum Buff { DamageUp = 0, DefUp = 0, HPUp = 0, MPUp = 0};
        
static void Main(string[] args)
{
    var arrEnum = Enum.GetValues<Buff>();

    foreach(Buff elem in arrEnum)
    {
        Console.WriteLine(elem.ToString());
    }
}

제가 작성한 코드입니다.
enum의 원소값을 중복으로 사용할 때 어떻게 동작할지 테스트 중이었습니다.
디버그를 통해 알아본 결과 arrEnum에는 DamageUp만 4개가 존재했고 foreach 내의 elem도 DamageUp이므로 DamageUp만 4번 출력될 줄 알았으나, DefUp만 4번 출력되었습니다.
어떤 요인으로 DefUp이 출력되는건가요?








[최초 등록일: ]
[최종 수정일: 9/2/2021]


비밀번호

댓글 작성자
 



2021-09-02 11시11분
농상 님이 이번 기회에 역어셈블러 등을 통해서 요인을 밝혀 주시면 어떨까요? 저는 농상 님이 충분히 하실 수 있을 거라 믿어 의심치 않습니다. (저라고 별 수 있겠습니까? 이런 경우 저 역시 그렇게 역어셈블 코드를 봐야 알 수 있습니다.)
정성태
2021-09-03 12시12분
[농상] 찾았습니다.
Enum클래스 내부의 ToString()의 동작방식에 따라 이렇게 결과가 나오는 것이 정상이었습니다.

Enum의 정보는 Flags 어트리뷰트 사용여부, 각 원소의 값들, 원소의 이름들로 구분하는데, 여기서 원소의 값들과 원소의 이름들을 배열로 생성하여 사용하고 있습니다.
원소들의 값과 원소들의 이름들은 같은 인덱스에 있는 것들끼리 1:1로 매칭됩니다.(예들 들어 Enum 첫번째 원소가 A = 3일 때, value[0]은 3, name[0]은 A와 같이 저장합니다.)
동작순서는
1. 찾고자하는 값을 원소들의 값을 저장한 배열에서 찾아, 인덱스를 얻는다.
2. 원소들의 이름을 저장한 배열에서, 얻은 인덱스에 있는 문자열을 반환한다.

여기서 1번 인덱스를 찾는 방식이 바이너리 서치로 찾고있습니다.
만약 모든 원소의 값이 동일하다면 중앙값부터 검사하도록 구현이 되어있기 때문에 반드시 배열의 가운데 인덱스를 반환합니다.
따라서 원소의 이름들 중 중앙에 있는 원소의 이름만 반환하기 때문에 발생하는 문제입니다.

.net 디자인 규칙중 CA1069가 열거형은 동일한 값을 가지지 않도록 하는 이유가 여기에 있습니다.
다만 CA1069 디자인 규칙은 위반해도 경고를 표시하지 않고 컴파일되므로 문제가 없다고 판단할 수 있습니다.

이것과 별개로 알아낸 점
1. Enum.GetValues()는 Enum값을 오름차순으로 정렬하여 반환해준다. -> 심지어 Enum 원소값들이 전부 음수여도 오름차순으로 반환합니다.
2. 만약 Enum 값이 같은 원소가 존재한다면 원소의 이름을 사전순으로 정렬하여 반환해준다. -> 이 특성으로 arrEnum의 원소들이 전부 DamageUp으로 채워졌습니다.
3. Array의 바이너리서치는 기본적으로 오른차순으로 정렬된 대상을 검사한다.
4. Array가 내림차순일 때 바이너리서치를 사용하려면 비교기준을 따로 인자로 전달해줘야 한다.
[guest]
2021-09-03 12시23분
[농상] .Net Framework 4.8 기준으로 분석했고, .Net 5.0 부터 기본 구조는 같지만 약간의 변화가 있었습니다.

.Net Framework 4.8에서는 원소 값과, 원소의 이름을 따로 생성하여 사용했지만 .Net 5.0부터 Flags 어트리뷰트 여부, 원소 값들, 원소 이름들을 필드로 가지는 EnumInfo라는 내부 클래스로 묶어서 관리하고 있습니다.

.Net Framework 4.8의 소스코드는 https://referencesource.microsoft.com 에서,
.Net 5.0의 소스코드는 https://source.dot.net 에서 확인할수 있었습니다.
[guest]
2021-09-03 12시27분
@농상 ^^b 이참에 그 내용을 정리하셔서 블로그를 꾸미셔도 좋을 듯합니다. ^^ 덧글로 남기에는 너무 아깝잖아요.

using System;
using System.Collections;

// enum Buff { DamageUp = 0, DefUp = 0, HPUp = 0, MPUp = 0 };

static class Program
{
    static void Main()
    {
        ArrayList arr = new ArrayList();
        arr.Add("DamageUp");
        arr.Add("DefUp");
        arr.Add("HPUp");
        arr.Add("MPUp");

        arr.Sort();

        Console.WriteLine(arr[arr.BinarySearch("HPUp", new Comparer())]);
        /* 출력
        DefUp
        */
    }
}

public class Comparer : IComparer
{
    // "return 0"은, enum의 값이 같으므로!
    public int Compare(object x, object y)
    {
        return 0;
    }
}
정성태

... 91  92  93  [94]  95  96  97 
NoWriterDateCnt.TitleFile(s)
111정성태3/19/20059740    답변글 [답변]: 닷넷 프레임워크 배포
107안연준3/17/20058978[-_-]스마트 클라이언트에 관련 된 질문[-_-]
110정성태3/19/20059827    답변글 [답변]: [-_-]스마트 클라이언트에 관련 된 질문[-_-]
116안연준3/21/20059381        답변글 [답변]: 친절한 답변 고맙습니다.
98김용국3/18/200511155정성태님... 연결이 준비됬습니다
99정성태3/2/200512023    답변글 [답변]: 정성태님... 연결이 준비됬습니다
100김용국3/18/20058859        답변글 [답변]: 죄송합니다! 급히올리느라 file path의 변경을 하지않고 그냥올렸네요....!
101정성태3/2/20059111            답변글 [답변]: [답변]: 죄송합니다! 급히올리느라 file path의 변경을 하지않고 그냥올렸네요....!
102김용국3/18/20059176                답변글 [답변]: 거듭죄송하네요..... 후~~~주소를 변경하고 빌드를 다시 했습니다....
103정성태3/2/20059037                    답변글 [답변]: [답변]: 거듭죄송하네요..... 후~~~주소를 변경하고 빌드를 다시 했습니다....
104김용국3/2/20059280                        답변글 [답변]: 네... 빨리 검토해 봐 주셔서 감사합니다~~
105정성태3/2/20058506                            답변글 [답변]: [답변]: 네... 빨리 검토해 봐 주셔서 감사합니다~~
106김용국3/2/20058989                                답변글 [답변]: 답변감사합니다!
91김용국2/28/200510820IE에 WindowsFormControl을 올려 실행하면 이런에러가 나네요???파일 다운로드1
92정성태2/28/200512113    답변글 [답변]: IE에 WindowsFormControl을 올려 실행하면 이런에러가 나네요???
93김용국2/28/200511052        답변글 [답변]: 답변감사합니다... 재질문을 드립니다
94정성태2/28/200511643            답변글 [답변]: [답변]: 답변감사합니다... 재질문을 드립니다
95김용국2/28/200511706                답변글 [답변]: IE주소창에서 해당주소로 실행을 해보니....디버깅 PopUp화면이...^
96정성태2/28/200510786                    답변글 [답변]: [답변]: IE주소창에서 해당주소로 실행을 해보니....디버깅 PopUp화면이...^
97김용국3/1/200511296                        답변글 [답변]: 준비되는데로 말씀드리겠습니다 ^^
88안지환2/22/200512825^^ 사이트 잘 들러보았습니다.
89정성태2/22/200512811    답변글 [답변]: ^^ 사이트 잘 들러보았습니다.
85한기열2/22/200511435정성태님 홈같은 부드러운 페이지 넘김?은 어떻게 구현하나요?
86정성태2/22/200512120    답변글 [답변]: 정성태님 홈같은 부드러운 페이지 넘김?은 어떻게 구현하나요? [2]
84김용국2/21/200512215Smart Client에 관한 문의 드립니다.
87정성태2/22/200512270    답변글 [답변]: Smart Client에 관한 문의 드립니다.
... 91  92  93  [94]  95  96  97