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

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;
    }
}
정성태

... 16  17  18  19  20  21  22  23  24  25  26  [27]  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
5219티지레몬9/9/20199668c# PCB 자동화 프로그램(윈도우 폼 위주로 작업) 제작 준비 [3]
5218민성9/9/20197703안녕하세요 WPF에서 xaml 안에 다른 xaml을 넣고 싶습니다. [1]파일 다운로드1
5216WPF9/8/20198797WPF에서 XAML Islands를 사용하여 Win2D를 사용하니 그래픽 품질이 저하됩니다. [2]파일 다운로드1
5215허송세월9/5/20198603중복실행 방지 관련 문의 [2]파일 다운로드1
5214Jang...9/4/20198225[DB 테이블의 데이터 변경에 대한 알림 처리] SQL-Server말고 MySQL은 불가능하겠죠? [1]
5213진우8/31/20197476c# 람다 변수 캡쳐 문의 [2]
5212심성보8/29/20199143Clipboard내 여러개의 이미지를 PictureBox로 불러오는 문제 [2]
5211최휘철8/24/20198320CLR20r3 관련된 윈도우 오류입니다. ㅠㅠ 도와주세요. / 아래글 관련하여 관련 파일 올려 드려요^^ [1]파일 다운로드1
5210최휘철8/23/201912232CLR20r3 관련된 윈도우 오류입니다. ㅠㅠ 도와주세요. [5]
5209세퉁8/21/20197867폰트 파일 속성 값을 가져오는 방법 질문 드립니다. [2]파일 다운로드1
5208홍길동8/19/20198697DebugDiag에서 .Net의 Stack Trace를 Windbg에서는 어떻게 볼 수 있나요? [3]
5207민성8/16/20197052네 소스 전체를 올리도록 하겠습니다. [2]파일 다운로드1
5206민성8/14/20197188전 재현 가능하다고 봤는데 다시올리도록 하겠습니다. [1]
5205miny...8/14/20198006안녕하세요 .WPF ListBox시 체크박스가 있는데 체크박스에서 체크가 되었는지 알수 있는 방법이 있을까요? [1]
5204영민8/8/201910784안녕하세요 디버깅시 콘솔창을 띠어서 볼수가 없나요? [7]
5202민성8/6/20197529WPF에서 <Application.Resources에 xaml에 있는 icon 값을 저장하고 xaml에 불러다 사용하고 싶은데요 [1]
5201김대훈8/3/20197130상속시 생성자에 대해 질문드립니다 [3]
5200농상7/30/20199827foreach로 데이터 변경 [2]
5190오리다람7/20/20197237질문드립니다. [3]
5189진우7/19/20197807C# 스레드풀 코어별 실행 문의 [2]
5188황태관7/19/20196996비주얼베이직 2019 실행 할때 마다.. [3]
5187플하7/19/20199813UWP 관련 궁금한 사항에 대해서 [1]
5186김대훈7/14/20198430박싱과 언박싱에 대해 [2]
5185농상7/13/20197284Nullable에 대해서 [1]
5184김대훈7/4/20197152저자님의 책을 다 본후에는 [2]
51837/2/20197866.NET Compact Freamwork 컨트롤러 더블버퍼링 [1]
... 16  17  18  19  20  21  22  23  24  25  26  [27]  28  29  30  ...