Home > Software design >  Parse string to enum with custom attribute
Parse string to enum with custom attribute

Time:04-04

I have an enum as follows. I also have a string in-progress I am trying to parse this string to the appropriate enum.

The issue being that enum try parse is checking on the name which means its failing. I need to parse it on this custom attribute.

I have been trying to see how I could get a list back of all of the fields within the enum and then test on the literal.

This would work but i have to specify each of the values within the enum in getfield

  var res = typeof(CarePlan.CarePlanActivityStatus)
                 .GetField(nameof(CarePlan.CarePlanActivityStatus.Cancelled))
                 .GetCustomAttribute<EnumLiteralAttribute>(false)
                 .Literal;
            

I tried something like this but Literal doesn't exist at this point apparently so this fails as well.

  var hold = typeof(CarePlan.CarePlanActivityStatus).GetFields().Where(a =>
            a.GetCustomAttributes<EnumLiteralAttribute>(false).Literal.Equals(data));

The enum

[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,
}

Isnt there a way to parse a string to an enum without making a large mess of a if statements to test it. Ideally i need to create a generic method as i have about 10 of these enums i need test.

CodePudding user response:

You can try with a extension method to read the Custom Atribute from Enums:

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}");
    }
}

and use it like this:

EnumExtensions.GetValueFromEnumMember<CarePlanActivityStatus>(stringValueToTest)

it returns the Enum Value

CodePudding user response:

I tried something like this but Literal doesn't exist at this point apparently so this fails as well.

I assume you're seeing this fail with a NullReferenceException? If you look at what GetFields() is actually returning, the first field it returns is value__, which doesn't have any attributes on it. So your GetCustomAttribute<EnumLiteralAttribute>() returns null, and accessing its Literal member fails with a NullReferenceException.

If you exclude this field from your test, or just make sure that you're safe to GetCustomAttribute returning null, everything works fine.

E.g.:

var hold = typeof(CarePlanActivityStatus).GetFields()
    .Where(a => a.GetCustomAttribute<EnumLiteralAttribute>(false)?.Literal == data);

See it on SharpLab.

  • Related