如何在C#中通过Display属性值获取对应的枚举成员?
Got it, let's tackle this problem: you have an enum decorated with Display attributes, and your external API returns the Name value from those attributes (like "CHANNEL_CHANNEL"), but you need to map that string back to the actual GTMType enum member. Here are a couple of robust approaches to handle this.
1. Basic Reflection-Based Method
First, we can create a generic helper method that uses reflection to scan the enum's fields and match the Display attribute's Name to the input string.
using System.ComponentModel; using System.Reflection; public static class EnumExtensions { public static TEnum GetEnumFromDisplayName<TEnum>(string displayName) where TEnum : Enum { // Iterate over all public static fields in the enum type foreach (FieldInfo field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static)) { // Check if the field has a Display attribute if (Attribute.GetCustomAttribute(field, typeof(DisplayAttribute)) is DisplayAttribute displayAttr) { if (displayAttr.Name.Equals(displayName, StringComparison.OrdinalIgnoreCase)) { return (TEnum)field.GetValue(null); } } // Optional: Fall back to matching the enum member name directly (in case of edge cases) else if (field.Name.Equals(displayName, StringComparison.OrdinalIgnoreCase)) { return (TEnum)field.GetValue(null); } } // Throw an exception if no match is found (you can also return default(TEnum) if preferred) throw new ArgumentException( $"No {typeof(TEnum).Name} member found with display name '{displayName}'", nameof(displayName)); } }
How to Use It
Update your GetDataForAccountByID method to call this helper:
public Account GetDataForAccountByID(string id) { AccountModel accountModel = GetDataFromAnotherSystem(id); var account = new Account { EmailAddress = accountModel.Email, GTMType = EnumExtensions.GetEnumFromDisplayName<GTMType>(accountModel.GTMType) }; return account; // Don't forget to return the constructed Account! }
2. Cached Version for Better Performance
If you're going to use this conversion frequently, reflection can add overhead. To optimize, we can cache the mapping between Display names and enum members once when the helper class is first accessed.
using System.ComponentModel; using System.Reflection; using System.Collections.Generic; public static class EnumDisplayNameCache<TEnum> where TEnum : struct, Enum { // Cache the display name -> enum member mapping private static readonly Dictionary<string, TEnum> _displayNameToEnumMap = new(StringComparer.OrdinalIgnoreCase); static EnumDisplayNameCache() { foreach (FieldInfo field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static)) { // Add Display attribute name to the cache if (Attribute.GetCustomAttribute(field, typeof(DisplayAttribute)) is DisplayAttribute displayAttr && !string.IsNullOrWhiteSpace(displayAttr.Name)) { _displayNameToEnumMap[displayAttr.Name] = (TEnum)field.GetValue(null); } // Add enum member name as a fallback _displayNameToEnumMap[field.Name] = (TEnum)field.GetValue(null); } } public static TEnum GetEnumFromDisplayName(string displayName) { if (_displayNameToEnumMap.TryGetValue(displayName, out TEnum enumValue)) { return enumValue; } throw new ArgumentException( $"No {typeof(TEnum).Name} member found with display name '{displayName}'", nameof(displayName)); } // Optional: Add a try-get method to handle invalid values gracefully public static bool TryGetEnumFromDisplayName(string displayName, out TEnum enumValue) { return _displayNameToEnumMap.TryGetValue(displayName, out enumValue); } }
Usage with Cache
public Account GetDataForAccountByID(string id) { AccountModel accountModel = GetDataFromAnotherSystem(id); // Use the cached helper if (!EnumDisplayNameCache<GTMType>.TryGetEnumFromDisplayName(accountModel.GTMType, out GTMType gtmType)) { // Handle invalid GTMType value here (e.g., throw custom exception, set default) throw new InvalidOperationException($"Invalid GTMType value received: {accountModel.GTMType}"); } var account = new Account { EmailAddress = accountModel.Email, GTMType = gtmType }; return account; }
Key Notes
- Make sure to include the
System.ComponentModelandSystem.Reflectionnamespaces in your code file. - The
StringComparison.OrdinalIgnoreCasemakes the matching case-insensitive (adjust this if you need exact case matching). - The try-get method is useful if you expect the API might return invalid values and want to handle them without throwing exceptions immediately.
内容的提问来源于stack exchange,提问作者ankur

