我正在构建一个函数来扩展Enum。解析概念
允许在没有找到Enum值的情况下解析默认值
不区分大小写
所以我写下了以下内容:
public static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
我得到一个错误约束不能是特殊类System.Enum。
很好,但是是否有一种变通方法来允许通用Enum,或者我将不得不模仿Parse函数并将类型作为属性传递,这将强制对代码进行丑陋装箱要求。
以下所有建议都非常感谢,谢谢。
已经确定(我已经离开了循环以保持大小写不敏感-我在解析XML时使用这个)
public static class EnumUtils
{
public static T ParseEnum<T>(string value, T defaultValue) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
}
编辑:(2015年2月16日)Christopher currents在下面的MSIL或f#中发布了一个编译器强制类型安全的通用解决方案,非常值得一看,并获得好评。如果解决方案在页面上方出现气泡,我将删除此编辑。
编辑2:(2021年4月13日)自从c# 7.3以来,这个问题已经得到解决和支持,我已经更改了公认的答案,尽管出于学术和历史兴趣,充分阅读顶部的答案是值得的:)
注意系统。Enum Parse()和TryParse()方法仍然有where struct约束,而不是where Enum,因此不会编译:
bool IsValid<TE>(string attempted) where TE : Enum
{
return Enum.TryParse(attempted, out TE _);
}
但这将:
bool Ok<TE>(string attempted) where TE : struct,Enum
{
return Enum.TryParse(attempted, out var _)
}
因此,where struct,Enum可能比where Enum更可取
我将Vivek的解决方案封装到一个可以重用的实用程序类中。请注意,你仍然应该在你的类型上定义类型约束“where T: struct, IConvertible”。
using System;
internal static class EnumEnforcer
{
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="typeParameterName">Name of the type parameter.</param>
/// <param name="methodName">Name of the method which accepted the parameter.</param>
public static void EnforceIsEnum<T>(string typeParameterName, string methodName)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
string message = string.Format(
"Generic parameter {0} in {1} method forces an enumerated type. Make sure your type parameter {0} is an enum.",
typeParameterName,
methodName);
throw new ArgumentException(message);
}
}
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="typeParameterName">Name of the type parameter.</param>
/// <param name="methodName">Name of the method which accepted the parameter.</param>
/// <param name="inputParameterName">Name of the input parameter of this page.</param>
public static void EnforceIsEnum<T>(string typeParameterName, string methodName, string inputParameterName)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
string message = string.Format(
"Generic parameter {0} in {1} method forces an enumerated type. Make sure your input parameter {2} is of correct type.",
typeParameterName,
methodName,
inputParameterName);
throw new ArgumentException(message);
}
}
/// <summary>
/// Makes sure that generic input parameter is of an enumerated type.
/// </summary>
/// <typeparam name="T">Type that should be checked.</typeparam>
/// <param name="exceptionMessage">Message to show in case T is not an enum.</param>
public static void EnforceIsEnum<T>(string exceptionMessage)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(exceptionMessage);
}
}
}