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

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

... [76]  77  78  79  80  81  82  83  84  85  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
589김희택3/2/20078989리소스 추가 방법에 대한 아티클을 보던중에 질문요... [1]파일 다운로드1
588이성진2/24/200711137웹 -> 스마트클라이언트 -> 웹서비스 의 세션 공유 방법 ? [1]
583김영민2/22/20079591Vista에서 "관리자 권한으로 실행"을 통해 실행한 프로세스의 동작
584정성태2/22/200710981    답변글 [답변]: Vista에서 "관리자 권한으로 실행"을 통해 실행한 프로세스의 동작
582한귀순2/22/20079630sqlhelper 의 updatedataset
585정성태2/23/20078928    답변글 [답변]: sqlhelper 의 updatedataset [1]
579futu...2/16/200710390VS2005의 스마트 클라이언트에서 웹브라우저 예제 질문입니다. [1]
578정해봉2/16/20079621IE Embeded Assambly 방식에서 CAS 설정 방법 [1]
575박성민2/12/200710181COM에 데이터 보내기 질문입니다. [1]
571엔틱스2/7/200710842그냥... 질문은 아닙니다만... [2]
5682/6/20078254이런 오류 화면을 어떻게 찾아봐야 - 알아봐야 - 하는지요?파일 다운로드1
569정성태2/6/20079430    답변글 [답변]: 이런 오류 화면을 어떻게 찾아봐야 - 알아봐야 - 하는지요? [1]
570정성태2/6/20079563        답변글 [답변]: [답변]: 이런 오류 화면을 어떻게 찾아봐야 - 알아봐야 - 하는지요?
5732/8/20078445            답변글 [답변]: [답변]: [답변]: 이런 오류 화면을 어떻게 찾아봐야 - 알아봐야 - 하는지요? [1]파일 다운로드1
565한귀순2/5/20079075typed dataset 의 유용성
566정성태2/6/200710713    답변글 [답변]: typed dataset의 유용성 [1]
564정민영2/5/20079241혹시 이런 경우 보신적 있으신가 궁금합니다..^^; [2]
563창민이2/2/20079377Visual C++ COM Objects Returning Recordsets 사용에 대해.. [3]
562현석1/29/20079241C# 스마트응용장치에서 아이콘 움직이게하는거 질문요 ^^ [1]파일 다운로드1
559초보1/27/200710609급 질문 입니다. visual studio 자동 종료에 대한 질문입니다. [2]
558즈믄1/26/200710559.Net Framework v2.0에서 Winform의 Panel에 Excel파일 보여주기 [2]
556정재우1/26/200710304vista에서 smartclient의 System.Security.PermissionsRegistryPermission 에러 [1]
555dev....1/25/2007120522005 WebBrowser내에서 팝업 처리 문제 관련 질문입니다.
561정성태1/29/200714888    답변글 [답변]: 2005 WebBrowser 내에서 팝업 처리 문제 관련 질문입니다.
554sky1/23/200710280<급질문> interop 를 사용함에 있어 [2]
557sky1/26/20078618    답변글 [답변]: <급질문> interop 를 사용함에 있어
... [76]  77  78  79  80  81  82  83  84  85  86  87  88  89  90  ...