code

Enum 값이 같으면 어떤 Enum 상수를 얻을 수 있습니까?

codestyles 2020. 12. 12. 10:53
반응형

Enum 값이 같으면 어떤 Enum 상수를 얻을 수 있습니까?


동일한 값을 가진 열거 형 상수가 두 개 이상있는 경우 어떤 상수에 대한 논리가 있습니까?

아래 변형을 시도했지만 합리적인 논리를 얻지 못했습니다.

주요 방법 :

public class Program
{
    public static void Main(string[] args)
    {
        Test a = 0;
        Console.WriteLine(a);
    }
}

첫 시도:

enum Test
{
    a1=0,
    a2=0,
    a3=0,
    a4=0,
}

산출:

a2

두 번째 시도 :

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4=0,
}

산출:

a4

세 번째 시도 :

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4,
}

산출:

a2

네 번째 시도 :

enum Test
{
    a1=0,
    a2=0,
    a3,
    a4
}

산출:

a1

문서는 실제로 주소 :

여러 열거 형 멤버에 동일한 기본 값이 있고 기본 값을 기반으로 열거 형 멤버 이름의 문자열 표현을 검색하려는 경우 코드에서 메서드가 반환 할 이름에 대해 가정하지 않아야합니다 .

(강조 추가됨)

그러나 이것이 결과가 무작위 임을 의미하지는 않습니다 . 이것이 의미 하는 바는 변경 될 수있는 구현 세부 사항이라는 것입니다 . 구현은 패치만으로 완전히 변경 될 수 있으며 컴파일러 (MONO, Roslyn 등)에 따라 다를 수 있으며 플랫폼마다 다를 수 있습니다.

시스템이이 있도록 설계되어있는 경우 필요 열거 형에 대한 역방향 조회 시간과 플랫폼에 걸쳐 일관성이 있음을, 다음 사용하지 마십시오 Enum.ToString . 하나는 그 세부에 의존하지 그래서 설계를 변경하거나 쓰기 자신의 방법 것입니다 일치합니다.

따라서 해당 구현에 의존하는 코드를 작성하지 마십시오. 그렇지 않으면 향후 릴리스에서 사용자 모르게 변경 될 위험을 감수해야합니다.


TL; DR : 열거 형의 모든 필드는 리플렉션에 의해 추출 된 다음 삽입 정렬 및 이진 검색에서 첫 번째 일치 값을 찾습니다.


콜 체인은 다음과 같습니다.

Enum.Tostring();
Enum.InternalFormat(RuntimeType eT, Object value);
Enum.GetName(Type enumType, Object value);
Type.GetEnumName(object value);

Type.GetEnumName(object value) 다음과 같이 구현됩니다.

    public virtual string GetEnumName(object value)
    {
        // standard argument guards...

        Array values = GetEnumRawConstantValues();
        int index = BinarySearch(values, value);

        if (index >= 0)
        {
            string[] names = GetEnumNames();
            return names[index];
        }

        return null;
    }

둘 다 GetEnumRawConstantValues()GetEnumNames()의존 GetEnumData(out string[] enumNames, out Array enumValues):

    private void GetEnumData(out string[] enumNames, out Array enumValues)
    {
        Contract.Ensures(Contract.ValueAtReturn<String[]>(out enumNames) != null);
        Contract.Ensures(Contract.ValueAtReturn<Array>(out enumValues) != null);

        FieldInfo[] flds = GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

        object[] values = new object[flds.Length];
        string[] names = new string[flds.Length];

        for (int i = 0; i < flds.Length; i++)
        {
            names[i] = flds[i].Name;
            values[i] = flds[i].GetRawConstantValue();
        }

        // Insertion Sort these values in ascending order.
        // We use this O(n^2) algorithm, but it turns out that most of the time the elements are already in sorted order and
        // the common case performance will be faster than quick sorting this.
        IComparer comparer = Comparer.Default;
        for (int i = 1; i < values.Length; i++)
        {
            int j = i;
            string tempStr = names[i];
            object val = values[i];
            bool exchanged = false;

            // Since the elements are sorted we only need to do one comparision, we keep the check for j inside the loop.
            while (comparer.Compare(values[j - 1], val) > 0)
            {
                names[j] = names[j - 1];
                values[j] = values[j - 1];
                j--;
                exchanged = true;
                if (j == 0)
                    break;
            }

            if (exchanged)
            {
                names[j] = tempStr;
                values[j] = val;
            }
        }

        enumNames = names;
        enumValues = values;
    }

, 다음 경우 GetFields(BindingFlags bindingAttr)에 리드 abstract방법을하지만, MSDN에 "GetFields"를 검색하면을 얻을 것입니다 EnumBuilder.GetFields(BindingFlags bindingAttr). 그리고 콜 체인을 따라 간다면 :

EnumBuilder.GetFields(BindingFlags bindingAttr);
TypeBuilder.GetFields(BindingFlags bindingAttr);
RuntimeType.GetFields(BindingFlags bindingAttr);
RuntimeType.GetFieldCandidates(String name, BindingFlags bindingAttr, bool allowPrefixLookup);
RuntimeTypeCache.GetFieldList(MemberListType listType, string name);
RuntimeTypeCache.GetMemberList<RuntimeFieldInfo>(ref MemberInfoCache<T> m_cache, MemberListType listType, string name, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.GetMemberList(MemberListType listType, string name, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.Populate(string name, MemberListType listType, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.GetListByName(char* pName, int cNameLen, byte* pUtf8Name, int cUtf8Name, MemberListType listType, CacheType cacheType);
MemberInfoCache<RuntimeFieldInfo>.PopulateFields(Filter filter);
// and from here, it is a wild ride...

그래서 Type.GetFields비고 를 인용하겠습니다 .

GetFields 메서드는 알파벳순 또는 선언 순서와 같은 특정 순서로 필드를 반환하지 않습니다. 필드가 반환되는 순서가 다르기 때문에 코드는 필드가 반환되는 순서에 의존해서는 안됩니다.

참고URL : https://stackoverflow.com/questions/37263124/which-enum-constant-will-i-get-if-the-enum-values-are-same

반응형