如果枚举值是相同的,我将得到哪个枚举常量
如果有多个具有相同值的枚举常量,那么是否有一个逻辑我得到的常量?
我尝试了下面的变化,但不能得到一个合理的逻辑。
主要方法:
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方法不会按特定顺序返回字段,例如按字母顺序或声明顺序。 您的代码不能依赖于返回字段的顺序,因为顺序不尽相同。