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

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

... [46]  47  48  49  50  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
3700박성훈2/18/201611171시작하세요! C# 6.0 프로그래밍 105쪽 예제 질문 [1]
3699박성훈2/18/201610772공부 방향성 질문 [2]
3698강준2/16/201611355Entity Framework 에서 Select for Update 가 가능한가요??? [1]
3697ds2/16/201610909어느 정도 문법을 알고 나면 [6]
3695Bere...2/15/201613121호출당한 메서드가 호출한 메서드를 알 수 있는 방법이 일반적인 방법 말고도 있을까요? [2]
3693조영준2/11/201613904UWP 앱을 만들고 있습니다. 죄송하지만 몇 가지 질문 드립니다. [4]
3692후배2/8/201612930html/css/js를 이용한 winForm의 UI표현이 가능 한가요? [3]
3690김대석2/5/201611357문의 드립니다. [2]
3687허재영2/3/201612959web api 보안관련 질문입니다. [2]
3685조진우2/1/201612889메인 응용 프로그램에서 DLL을 실시간으로 접근하여 사용하는데 이것을 모니터링 할 수 있을 까요? [1]
3684나그네1/27/201612223안녕하세요..wcf 관련하여 질문있습니다. [4]파일 다운로드1
3683김태형1/25/201612494 안녕하세요 저작도서를 구매하려는데 한가지 문의 사항이 있어서 질문드립니다. [1]
3681이영균1/8/201615058IE브라우저 추가기능관리의 항목을 사용함으로 c#코드로 변경을 하려고 합니다. [8]
3680후배1/6/201615281추천할만한 소켓 라이브러리 있으신가요? [2]
3679초록물꼬기1/6/201614154Parallel.For 에서 동기화문제에 관한 질문입니다. [11]파일 다운로드1
3678김민우1/3/201612631IHS 오류에 대한 질문입니다. [2]파일 다운로드1
3677초록색우산12/31/201514250HTTP 통신 - WebClient 이용시 한글깨짐 현상 발생 [2]
3676서정열12/31/201513085안녕하세요 WebService SoapExtensionImporter 에 대해서 질문드립니다. [3]
3675차가워12/30/201512163윈폼, 폼인폼 상황에서 하위컨트롤 포커스 문제 [1]
3673Sung...12/24/201513227UWP예외 발생 : 'System.Runtime.InteropServices.COMException'(mscorlib.ni.dll) 해결방법 [2]
3672Sung...12/23/201512354global::System.Diagnostics.Debugger.Break();가 노랗게 표시될시 [2]
3671이상준12/22/201516606한글 키보드 입력에 대해서 질문이 있습니다. [3]
3670Sung...12/18/201513371UWP 주기적으로 신호를 보내고 클라이언트에서 신호가 오면 받는 프로그램을 하려고 합니다. [5]
3669다비드12/18/201511682인터넷 임시파일 삭제 관련 질문. [1]
3668김치사발면12/16/201511129템플릿이 자꾸 초기화? 되버리네요 [1]
3667김치사발면12/15/201511029템플릿 설정 추가 질문 [1]파일 다운로드1
... [46]  47  48  49  50  51  52  53  54  55  56  57  58  59  60  ...