Подтвердить что ты не робот

Использование EnumMemberAttribute и автоматическое преобразование строк

У меня есть следующий код

[DataContract]
public enum StatusType
{
    [EnumMember(Value = "A")]
    All,
    [EnumMember(Value = "I")]
    InProcess,
    [EnumMember(Value = "C")]
    Complete,
}

Я хотел бы сделать следующее:

 var s = "C";
 StatusType status = SerializerHelper.ToEnum<StatusType>(s);   //status is now StatusType.Complete
 string newString = SerializerHelper.ToEnumString<StatusType>(status);   //newString is now "C"

Я сделал вторую часть с помощью DataContractSerializer (см. код ниже), но это похоже на большую работу.

Я пропустил что-то очевидное? Идеи? Спасибо.

    public static string ToEnumString<T>(T type)
    {
        string s;
        using (var ms = new MemoryStream())
        {
            var ser = new DataContractSerializer(typeof(T));
            ser.WriteObject(ms, type);
            ms.Position = 0;
            var sr = new StreamReader(ms);
            s = sr.ReadToEnd();
        }
        using (var xml = new XmlTextReader(s, XmlNodeType.Element, null))
        {
            xml.MoveToContent();
            xml.Read();
            return xml.Value;
        }
    }
4b9b3361

Ответ 1

Вот мое предложение - оно должно дать вам представление о том, как это сделать (также проверьте Получение атрибутов значения Enum):

public static string ToEnumString<T>(T type)
{
    var enumType = typeof (T);
    var name = Enum.GetName(enumType, type);
    var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
    return enumMemberAttribute.Value;
}

public static T ToEnum<T>(string str)
{
    var enumType = typeof(T);
    foreach (var name in Enum.GetNames(enumType))
    {
        var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
        if (enumMemberAttribute.Value == str) return (T)Enum.Parse(enumType, name);
    }
    //throw exception or whatever handling you want or
    return default(T);
}

Ответ 2

Вы можете использовать отражение, чтобы получить значение EnumMemberAttribute.

public static string ToEnumString<T>(T instance)
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("instance", "Must be enum type");
    string enumString = instance.ToString();
    var field = typeof(T).GetField(enumString);
    if (field != null) // instance can be a number that was cast to T, instead of a named value, or could be a combination of flags instead of a single value
    {
        var attr = (EnumMemberAttribute)field.GetCustomAttributes(typeof(EnumMemberAttribute), false).SingleOrDefault();
        if (attr != null) // if there no EnumMember attr, use the default value
            enumString = attr.Value;
    }
    return enumString;
}

В зависимости от того, как работает ваш ToEnum, вы также можете использовать такой подход. Кроме того, тип может быть выведен при вызове ToEnumString, например. SerializerHelper.ToEnumString(status);

Ответ 3

Если ваш проект ссылается на Newtonsoft.Json (что не так в наши дни?!), то существует простое однострочное решение, которое не требует отражения:

public static string ToEnumString<T>(T value)
{
   return JsonConvert.SerializeObject(value).Replace("\"", "");
}

public static T ToEnum<T>(string value)
{
   return JsonConvert.DeserializeObject<T>($"\"{value}\"");
}

Метод ToEnumString будет работать только в том случае, если у вас StringEnumConverter зарегистрировано в JsonSerializerSettings (см. JavaScriptSerializer - JSON-сериализация enum в виде строки), например

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    Converters = { new StringEnumConverter() }
};

Еще одним преимуществом этого метода является то, что если только некоторые из ваших элементов enum имеют атрибут member, все по-прежнему работает, как ожидалось, например,

public enum CarEnum
{
    Ford,
    Volkswagen,
    [EnumMember(Value = "Aston Martin")]
    AstonMartin
}