如果枚举值是相同的,我将得到哪个枚举常量

如果有多个具有相同值的枚举常量,那么是否有一个逻辑我得到的常量?

我尝试了下面的变化,但不能得到一个合理的逻辑。

主要方法:

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 

文件实际上解决这个问题:

如果多个枚举成员具有相同的基础值,并且您尝试根据基础值检索枚举成员名称的string表示forms,那么您的代码不应该对该方法返回的名称做任何假设

(强调加)

但是,这并不意味着结果是随机的 。 这意味着它是一个可能会改变的实现细节 。 实现可以完全改变只是一个补丁,可以在编译器(MONO,Roslyn等)不同,并在不同的平台上有所不同。

如果您的系统devise为需要对枚举的反向查找随时间和平台一致,则不要使用 Enum.ToString 。 要么改变你的devise,所以它不依赖于这个细节,或者写出你自己的一致方法。

所以你不应该编写依赖于这个实现的代码,否则你将面临在未来版本中不知情的情况下会改变的风险。

TL; DR:枚举的所有字段将被reflection提取,然后插入sorting和二进制search第一个匹配的值。


呼叫链看起来是这样的:

 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上search“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方法不会按特定顺序返回字段,例如按字母顺序或声明顺序。 您的代码不能依赖于返回字段的顺序,因为顺序不尽相同。