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

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

... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
947김순조1/24/201114539.NET based Com에서 Native ActiveX로 이벤트 보내기?? [2]파일 다운로드1
943김기룡1/3/201117556닷넷 에러시 조치사항관련... [2]
942김기룡12/27/201012516Thread 안정성 관련 문의 드립니다. [2]
941최광욱12/20/201012222정성태님 올리신 글중에 [1]
940최광욱12/20/201013806Assembly Unloading 관련해서 [2]
939최광욱12/20/201012860IIS 로그 읽기 [1]
938날쌘돌이12/14/201013058자바로 asp.net 인증하기 [3]
935김기룡12/13/201023314c#에서 c++로 개발된 dll에 byte[] 전달 관련하여 문의 드립니다. [6]
934임동찬12/7/201011440System.Reflection.Assembly.GetTypes() 메서드에 대해 [1]
929김준호12/2/201011682안녕하세요 비주얼베이직 2005 닷넷 관련 문의입니다 [1]
928김준호11/30/201012324안녕하세요 비주얼베이직 2005 닷넷 관련 문의입니다 [1]파일 다운로드1
927임동찬11/30/201013446Windows\\Temp 폴더의 이름모를 .tmp 파일들에 대해서 [1]
926이승규11/26/201033153IP접속 시도시 ORA-12504 에러 [1]
925임동찬11/11/201011300다른 프로그램의 컨트롤 건드려보기_추가질문(2) [1]
924임동찬11/10/201012203다른 프로그램의 컨트롤 건드려보기_추가질문 [1]
923임동찬11/9/201014632다른 프로그램의 컨트롤 건드려보기 [1]
922박태근11/2/201013215html5의 shape파일 관련 [1]파일 다운로드1
921박태근11/1/201013928DataTable 의 Binary변환! [1]
920김재영10/26/201014005GAC에 등록된 어셈블리를 Visual Studio에서 참조 대화상자에 보이게 할려면 어떤 방법이 있습니까? [2]
919임동찬10/22/201012733IStream [1]
918임동찬10/21/201012065System.Runtime.InteropServices.ComTypes.IStream 관련 [1]
917한귀순10/20/201016074IIS 최초 loading 시 속도 [2]
916임동찬10/15/201012452file lock 관련 [2]
915오병태10/11/201011158바쁘신대 답변 감사드립니다. [1]
914오병태10/11/201011226감사드립니다. 염치없지만 또 한번 문의드립니다. [2]
912오병태10/11/201011477윈도우즈 인증서 관련해서 문의를 드립니다.
... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...