using System.Diagnostics.CodeAnalysis; namespace AIStudio.Settings; /// /// Reads the name of an enum member, and nothing else. /// /// /// For values somebody wrote by hand, such as those of a configuration plugin. Enum.TryParse /// accepts more than a name: a number, which becomes whichever member has that value or a value /// no member has, and several names separated by commas, which it combines bit by bit as if the /// enum were a set of flags. The enums read from a configuration are no such sets, so /// "SEMANTIC_SEARCH, EVERY_MESSAGE" would quietly become EVERY_MESSAGE, and "HIGH, MEDIUM" a /// confidence level which no provider reaches. Only a single name counts here, ignoring case and /// surrounding white space as Enum.TryParse does. /// public static class EnumNames { /// /// Reads the name of a member of the given enum. /// /// The text to read. /// The member named, or the default when the text names none. /// The enum to read a member of. /// True when the text names exactly one member. public static bool TryParse(string? text, out TEnum value) where TEnum : struct, Enum { if (TryParse(typeof(TEnum), text, out var member)) { value = (TEnum)member; return true; } value = default; return false; } /// /// Reads the name of a member of the given enum type. /// /// The enum type to read a member of. /// The text to read. /// The member named, or null when the text names none. /// True when the text names exactly one member. public static bool TryParse(Type enumType, string? text, [NotNullWhen(true)] out object? value) { value = null; if (string.IsNullOrWhiteSpace(text)) return false; var trimmedText = text.Trim(); var name = Enum.GetNames(enumType).FirstOrDefault(candidate => candidate.Equals(trimmedText, StringComparison.OrdinalIgnoreCase)); if (name is null) return false; value = Enum.Parse(enumType, name); return true; } }