将字符串解析为具有自定义属性的枚举
Parse string to enum with custom attribute
我有一个枚举如下。我还有一个字符串 in-progress
我正在尝试将此字符串解析为适当的枚举。正如下面的测试所见,我们想要解析一个字符串和 return 枚举
[Fact]
public void TestParseOfEnum()
{
var data = "not-started";
var parsed = EnumExtensions.GetValueFromEnumMember<CarePlan.CarePlanActivityStatus>(data);
parsed.ShouldBe(CarePlan.CarePlanActivityStatus.NotStarted);
}
问题是 enum try parse 正在检查名称,这意味着它失败了。我需要在这个自定义属性上解析它。
CarePlan.CarePlanActivityStatus status
Enum.TryParse("in-progress", out status)
尝试解析不会找到它,因为尝试解析检查名称字段而不是此枚举中的自定义属性。所以这会 return false 并且找不到我的枚举
我一直在尝试查看如何获取枚举中所有字段的列表,然后对文字进行测试。
这可行,但我必须在 getfield
的枚举中指定每个值
var res = typeof(CarePlan.CarePlanActivityStatus)
.GetField(nameof(CarePlan.CarePlanActivityStatus.Cancelled))
.GetCustomAttribute<EnumLiteralAttribute>(false)
.Literal;
我试过类似的方法,但此时 Literal 显然不存在,所以也失败了。
var hold = typeof(CarePlan.CarePlanActivityStatus).GetFields().Where(a =>
a.GetCustomAttributes<EnumLiteralAttribute>(false).Literal.Equals(data));
枚举
我为 fhir 库使用的 nuget 包是 Hl7.Fhir.R4
[FhirEnumeration("CarePlanActivityStatus")]
public enum CarePlanActivityStatus
{
/// <summary>
/// Care plan activity is planned but no action has yet been taken.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("not-started", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Not Started")] NotStarted,
/// <summary>
/// Appointment or other booking has occurred but activity has not yet begun.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("scheduled", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Scheduled")] Scheduled,
/// <summary>
/// Care plan activity has been started but is not yet complete.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("in-progress", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("In Progress")] InProgress,
/// <summary>
/// Care plan activity was started but has temporarily ceased with an expectation of resumption at a future time.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("on-hold", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("On Hold")] OnHold,
/// <summary>
/// Care plan activity has been completed (more or less) as planned.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("completed", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Completed")] Completed,
/// <summary>
/// The planned care plan activity has been withdrawn.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("cancelled", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Cancelled")] Cancelled,
/// <summary>
/// The planned care plan activity has been ended prior to completion after the activity was started.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("stopped", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Stopped")] Stopped,
/// <summary>
/// The current state of the care plan activity is not known. Note: This concept is not to be used for "other" - one of the listed statuses is presumed to apply, but the authoring/source system does not know which one.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("unknown", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Unknown")] Unknown,
/// <summary>
/// Care plan activity was entered in error and voided.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("entered-in-error", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Entered in Error")] EnteredInError,
}
// 我用
测试过的所有示例
我为 fhir 库使用的 nuget 包是 Hl7.Fhir.R4
public static class EnumExtensions
{
public static T GetValueFromEnumMember<T>(string value) where T : Enum
{
{
// Doesnt work as .Literal shows as red not valid.
var hold = typeof(CarePlan.CarePlanActivityStatus).GetFields().Where(a =>
a.GetCustomAttributes<EnumLiteralAttribute>(false).Literal.Equals(data));
// doesnt work as its returning the string i need it to return the enum
var res = typeof(CarePlan.CarePlanActivityStatus)
.GetField(nameof(CarePlan.CarePlanActivityStatus.Cancelled))
.GetCustomAttribute<EnumLiteralAttribute>(false)
.Literal;
// neither of the following two work as they are just looping though and i cant find the enum they find.
foreach (CarePlan.CarePlanActivityStatus status in (CarePlan.CarePlanActivityStatus[])Enum.GetValues(
typeof(CarePlan.CarePlanActivityStatus)))
{
}
foreach (string i in Enum.GetNames(typeof(CarePlan.CarePlanActivityStatus)))
{
// var res = typeof(CarePlan.CarePlanActivityStatus)
// .GetField(nameof(CarePlan.CarePlanActivityStatus[i]))
// .GetCustomAttribute<EnumLiteralAttribute>(false)
// .Literal;
//
// Console.WriteLine($" {res}" );
//
// Console.WriteLine($" {i}" );
}
}
有没有一种方法可以将字符串解析为枚举,而无需使用大量 if 语句来测试它。理想情况下,我需要创建一个通用方法,因为我有大约 10 个这些枚举需要测试。
您可以尝试使用扩展方法从枚举中读取自定义属性:
public static class EnumExtensions
{
public static T GetValueFromEnumMember<T>(string value) where T: Enum
{
var type = typeof(T);
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(EnumMemberAttribute)) as EnumMemberAttribute;
if (attribute != null)
{
if (attribute.Value == value)
return (T)field.GetValue(null);
}
else
{
if (field.Name == value)
return (T)field.GetValue(null);
}
}
throw new ArgumentException($"unknow value: {value}");
}
}
并像这样使用它:
EnumExtensions.GetValueFromEnumMember<CarePlanActivityStatus>(stringValueToTest)
它 returns 枚举值
I tried something like this but Literal doesn't exist at this point apparently so this fails as well.
您问题中的一个错误是您调用的是 GetCustomAttributes
而不是 GetCustomAttribute
。 GetCustomAttributes
returns 一个 IEnumerable<EnumLiteralAttribute>
,当然不会有 Literal
属性。 GetCustomAttribute
returns 单个 EnumLiteralAttribute
(或 null
),您可以访问其 Literal
属性.
这会产生错误消息:
error CS1061: 'IEnumerable<EnumLiteralAttribute>' does not contain a definition for 'Literal' and no accessible extension method 'Literal' accepting a first argument of type 'IEnumerable<EnumLiteralAttribute>' could be found (are you missing a using directive or an assembly reference?)
另一个问题是这将失败并显示 NullReferenceException
。如果您查看 GetFields()
实际返回的内容,它 returns 的第一个字段是 value__
,它没有任何属性。因此,您的 GetCustomAttribute<EnumLiteralAttribute>()
returns null
和访问其 Literal
成员失败并显示 NullReferenceException
.
如果您从测试中排除此字段,或者只是确保您可以安全地 GetCustomAttribute
返回 null
,一切正常。
例如:
var hold = typeof(CarePlanActivityStatus).GetFields()
.Where(a => a.GetCustomAttribute<EnumLiteralAttribute>(false)?.Literal == data);
如果您随后想要访问具有该属性的枚举,请调用 FieldInfo
的 GetValue
方法:
var hold = typeof(CarePlanActivityStatus).GetFields()
.FirstOrDefault(a => a.GetCustomAttribute<EnumLiteralAttribute>(false)?.Literal == data)
?.GetValue(null);
根据评论,您可以在一个字段上有多个属性,并且您想查看它们的任何 Literal
属性是否匹配 data
.
在这种情况下,您将希望使用 GetCustomAttributes
获取所有属性,但随后您希望遍历它们并查看 上的 Literal
属性是否为任何 其中符合您的要求。最简单的方法是使用 Linq 的 Any
:
string data = "cancelled";
var hold = typeof(CarePlanActivityStatus).GetFields()
.FirstOrDefault(a => a.GetCustomAttributes<EnumLiteralAttribute>(false)
.Any(x => x.Literal == data))
?.GetValue(null);
hold.Dump();
你可以使用这个:
var enumType = typeof(CarePlanActivityStatus);
FieldInfo field = enumType.GetField(nameof(CarePlanActivityStatus.Cancelled));
var enumLiteralAttribute = field.GetCustomAttribute<EnumLiteralAttribute>(false);
WriteLine(enumLiteralAttribute.Name); // canceled
WriteLine(enumLiteralAttribute.Url); // http://hl7.org/fhir/care-plan-activity-status
我有一个枚举如下。我还有一个字符串 in-progress
我正在尝试将此字符串解析为适当的枚举。正如下面的测试所见,我们想要解析一个字符串和 return 枚举
[Fact]
public void TestParseOfEnum()
{
var data = "not-started";
var parsed = EnumExtensions.GetValueFromEnumMember<CarePlan.CarePlanActivityStatus>(data);
parsed.ShouldBe(CarePlan.CarePlanActivityStatus.NotStarted);
}
问题是 enum try parse 正在检查名称,这意味着它失败了。我需要在这个自定义属性上解析它。
CarePlan.CarePlanActivityStatus status
Enum.TryParse("in-progress", out status)
尝试解析不会找到它,因为尝试解析检查名称字段而不是此枚举中的自定义属性。所以这会 return false 并且找不到我的枚举
我一直在尝试查看如何获取枚举中所有字段的列表,然后对文字进行测试。
这可行,但我必须在 getfield
的枚举中指定每个值 var res = typeof(CarePlan.CarePlanActivityStatus)
.GetField(nameof(CarePlan.CarePlanActivityStatus.Cancelled))
.GetCustomAttribute<EnumLiteralAttribute>(false)
.Literal;
我试过类似的方法,但此时 Literal 显然不存在,所以也失败了。
var hold = typeof(CarePlan.CarePlanActivityStatus).GetFields().Where(a =>
a.GetCustomAttributes<EnumLiteralAttribute>(false).Literal.Equals(data));
枚举
我为 fhir 库使用的 nuget 包是 Hl7.Fhir.R4
[FhirEnumeration("CarePlanActivityStatus")]
public enum CarePlanActivityStatus
{
/// <summary>
/// Care plan activity is planned but no action has yet been taken.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("not-started", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Not Started")] NotStarted,
/// <summary>
/// Appointment or other booking has occurred but activity has not yet begun.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("scheduled", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Scheduled")] Scheduled,
/// <summary>
/// Care plan activity has been started but is not yet complete.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("in-progress", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("In Progress")] InProgress,
/// <summary>
/// Care plan activity was started but has temporarily ceased with an expectation of resumption at a future time.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("on-hold", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("On Hold")] OnHold,
/// <summary>
/// Care plan activity has been completed (more or less) as planned.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("completed", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Completed")] Completed,
/// <summary>
/// The planned care plan activity has been withdrawn.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("cancelled", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Cancelled")] Cancelled,
/// <summary>
/// The planned care plan activity has been ended prior to completion after the activity was started.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("stopped", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Stopped")] Stopped,
/// <summary>
/// The current state of the care plan activity is not known. Note: This concept is not to be used for "other" - one of the listed statuses is presumed to apply, but the authoring/source system does not know which one.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("unknown", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Unknown")] Unknown,
/// <summary>
/// Care plan activity was entered in error and voided.
/// (system: http://hl7.org/fhir/care-plan-activity-status)
/// </summary>
[EnumLiteral("entered-in-error", "http://hl7.org/fhir/care-plan-activity-status"), Hl7.Fhir.Utility.Description("Entered in Error")] EnteredInError,
}
// 我用
测试过的所有示例我为 fhir 库使用的 nuget 包是 Hl7.Fhir.R4
public static class EnumExtensions
{
public static T GetValueFromEnumMember<T>(string value) where T : Enum
{
{
// Doesnt work as .Literal shows as red not valid.
var hold = typeof(CarePlan.CarePlanActivityStatus).GetFields().Where(a =>
a.GetCustomAttributes<EnumLiteralAttribute>(false).Literal.Equals(data));
// doesnt work as its returning the string i need it to return the enum
var res = typeof(CarePlan.CarePlanActivityStatus)
.GetField(nameof(CarePlan.CarePlanActivityStatus.Cancelled))
.GetCustomAttribute<EnumLiteralAttribute>(false)
.Literal;
// neither of the following two work as they are just looping though and i cant find the enum they find.
foreach (CarePlan.CarePlanActivityStatus status in (CarePlan.CarePlanActivityStatus[])Enum.GetValues(
typeof(CarePlan.CarePlanActivityStatus)))
{
}
foreach (string i in Enum.GetNames(typeof(CarePlan.CarePlanActivityStatus)))
{
// var res = typeof(CarePlan.CarePlanActivityStatus)
// .GetField(nameof(CarePlan.CarePlanActivityStatus[i]))
// .GetCustomAttribute<EnumLiteralAttribute>(false)
// .Literal;
//
// Console.WriteLine($" {res}" );
//
// Console.WriteLine($" {i}" );
}
}
有没有一种方法可以将字符串解析为枚举,而无需使用大量 if 语句来测试它。理想情况下,我需要创建一个通用方法,因为我有大约 10 个这些枚举需要测试。
您可以尝试使用扩展方法从枚举中读取自定义属性:
public static class EnumExtensions
{
public static T GetValueFromEnumMember<T>(string value) where T: Enum
{
var type = typeof(T);
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(EnumMemberAttribute)) as EnumMemberAttribute;
if (attribute != null)
{
if (attribute.Value == value)
return (T)field.GetValue(null);
}
else
{
if (field.Name == value)
return (T)field.GetValue(null);
}
}
throw new ArgumentException($"unknow value: {value}");
}
}
并像这样使用它:
EnumExtensions.GetValueFromEnumMember<CarePlanActivityStatus>(stringValueToTest)
它 returns 枚举值
I tried something like this but Literal doesn't exist at this point apparently so this fails as well.
您问题中的一个错误是您调用的是 GetCustomAttributes
而不是 GetCustomAttribute
。 GetCustomAttributes
returns 一个 IEnumerable<EnumLiteralAttribute>
,当然不会有 Literal
属性。 GetCustomAttribute
returns 单个 EnumLiteralAttribute
(或 null
),您可以访问其 Literal
属性.
这会产生错误消息:
error CS1061: 'IEnumerable<EnumLiteralAttribute>' does not contain a definition for 'Literal' and no accessible extension method 'Literal' accepting a first argument of type 'IEnumerable<EnumLiteralAttribute>' could be found (are you missing a using directive or an assembly reference?)
另一个问题是这将失败并显示 NullReferenceException
。如果您查看 GetFields()
实际返回的内容,它 returns 的第一个字段是 value__
,它没有任何属性。因此,您的 GetCustomAttribute<EnumLiteralAttribute>()
returns null
和访问其 Literal
成员失败并显示 NullReferenceException
.
如果您从测试中排除此字段,或者只是确保您可以安全地 GetCustomAttribute
返回 null
,一切正常。
例如:
var hold = typeof(CarePlanActivityStatus).GetFields()
.Where(a => a.GetCustomAttribute<EnumLiteralAttribute>(false)?.Literal == data);
如果您随后想要访问具有该属性的枚举,请调用 FieldInfo
的 GetValue
方法:
var hold = typeof(CarePlanActivityStatus).GetFields()
.FirstOrDefault(a => a.GetCustomAttribute<EnumLiteralAttribute>(false)?.Literal == data)
?.GetValue(null);
根据评论,您可以在一个字段上有多个属性,并且您想查看它们的任何 Literal
属性是否匹配 data
.
在这种情况下,您将希望使用 GetCustomAttributes
获取所有属性,但随后您希望遍历它们并查看 上的 Literal
属性是否为任何 其中符合您的要求。最简单的方法是使用 Linq 的 Any
:
string data = "cancelled";
var hold = typeof(CarePlanActivityStatus).GetFields()
.FirstOrDefault(a => a.GetCustomAttributes<EnumLiteralAttribute>(false)
.Any(x => x.Literal == data))
?.GetValue(null);
hold.Dump();
你可以使用这个:
var enumType = typeof(CarePlanActivityStatus);
FieldInfo field = enumType.GetField(nameof(CarePlanActivityStatus.Cancelled));
var enumLiteralAttribute = field.GetCustomAttribute<EnumLiteralAttribute>(false);
WriteLine(enumLiteralAttribute.Name); // canceled
WriteLine(enumLiteralAttribute.Url); // http://hl7.org/fhir/care-plan-activity-status