2014-09-03 14 views
5

Chcę serializować typ wyliczeniowy, aby zwracał tablicę z wyliczeniami jako obiekt zawierający zarówno "wartość", "nazwę" i adnotację danych wartość. Potrzebuję pomocy w serializacji. Oto co zrobiłem do tej pory: wyliczenia:Niestandardowa serializacja Json.NET typu wyliczeniowego z adnotacją danych

public enum Status 
{ 
    [Display(Name="Active status")] 
    Active = 1, 
    [Display(Name = "Deactive status")] 
    Deactive = 2, 
    [Display(Name = "Pending status")] 
    Pending = 3 
} 

DTO obiektu, który powinien być w odcinkach:

public class ProjectDto 
{ 
    public Type StatusEnum { get; set; } 

    public Status CurrentStatus { get; set; } 
} 

Przypisanie wartości:

var project = new ProjectDto 
{ 
    CurrentStatus = Status.Active, 
    StatusEnum = typeof (Status) 
}; 
var output = JsonConvert.SerializeObject(project); 

Aby uzyskać wartości z wyliczenia używam:

Enum.GetNames(typeof(Status)) //To get the names in the enum 
Enum.GetValues(typeof(Status)) //To get the values in the enum 

uzyskać wartość nazwa adnotacji danych jest nieco trudniejsze, ale znalazłem pomoc w tym artykule: http://geeksharp.com/2011/11/02/power-up-your-enumerations/ Stworzyli metody pomocnika, który będzie uzyskać wartość zapisaną w adnotacji danych przy użyciu:

public static string GetAttributeValue<T>(this Enum e, 
    Func<T, object> selector) where T : Attribute 
{ 
    var output = e.ToString(); 
    var member = e.GetType().GetMember(output).First(); 
    var attributes = member.GetCustomAttributes(typeof(T), false); 

    if (attributes.Length > 0) 
    { 
     var firstAttr = (T)attributes[0]; 
     var str = selector(firstAttr).ToString(); 
     output = string.IsNullOrWhiteSpace(str) ? output : str; 
    } 

    return output; 
} 

I można uzyskać wartość używając:

.GetAttributeValue<DisplayAttribute>(y => y.Name) 

Wyjście powinno być coś jak

{ 
    statusEnum: [ 
     { "value": "1", "name": "Active", "label": "Active status" }, 
     { "value": "2", "name": "Deactive", "label": "Deactive status" }, 
     { "value": "3", "name": "Pending", "label": "Pending status" } 
    ], 
    currentStatus: { "value": "1", "name": "Active", "label": "Active status" } 
} 

jak wspomniano Potrzebuję pomocy w tworzeniu niestandardowego Json.NET serializacji i deserializacji, aby uzyskać pożądany wynik. Jakakolwiek pomoc byłaby apriciated.

+1

Czy właściwość 'CurrentStatus' jest tablicą? Ponadto, w jaki sposób 'StatusEnum', który jest typu' System.Type', jest serializowany do obiektu, który wygląda tak? –

+1

Przepraszam, dobry połów. Tęskniłem za tym, że pomieszałem statusEnum i currentStatus na wyjściu, teraz naprawiłem.statusEnum powinien reprezentować typ wyliczania statusu wraz ze wszystkimi jego wartościami, podczas gdy currentStatus powinien reprezentować pojedynczą wartość wyliczenia, która została "wybrana". –

Odpowiedz

7

Ok, może to prawdopodobnie być czyszczone się trochę, ale chciałbym napisać dwa niestandardowe konwertery: jedną dla typu Enum, a inna dla wartości ENUM:

stworzyłem niestandardowej klasy do serializacji do końca spowodować, że chcesz:

public class EnumValue 
{ 
    public int Value { get; set; } 

    public string Name { get; set; } 

    public string Label { get; set; } 
} 

jak i statyczną klasę, która robi niektóre legwork do tworzenia wystąpień tego typu od Enum s i wartości eNUM:

public static class EnumHelpers 
{ 
    public static EnumValue GetEnumValue(object value, Type enumType) 
    { 
     MemberInfo member = enumType.GetMember(value.ToString())[0]; 

     DisplayAttribute attribute = 
      member.GetCustomAttribute<DisplayAttribute>(); 

     return new EnumValue 
     { 
      Value = (int)value, 
      Name = Enum.GetName(enumType, value), 
      Label = attribute.Name 
     }; 
    } 

    public static EnumValue[] GetEnumValues(Type enumType) 
    { 
     Array values = Enum.GetValues(enumType); 

     EnumValue[] result = new EnumValue[values.Length]; 

     for (int i = 0; i < values.Length; i++) 
     { 
      result[i] = GetEnumValue(
       values.GetValue(i), 
       enumType); 
     } 

     return result; 
    } 
} 

Następnie są dwie klasy konwerterów. Ta pierwsza serializes System.Type do obiektu chciałeś:

public class EnumTypeConverter : JsonConverter 
{ 
    public override void WriteJson(
     JsonWriter writer, 
     object value, 
     JsonSerializer serializer) 
    { 
     if (value == null) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     EnumValue[] values = EnumHelpers.GetEnumValues((Type)value); 

     serializer.Serialize(writer, values); 
    } 

    public override object ReadJson(
     JsonReader reader, 
     Type objectType, 
     object existingValue, 
     JsonSerializer serializer) 
    { 
     throw new NotSupportedException(); 
    } 

    public override bool CanRead { get { return false; } } 

    public override bool CanConvert(Type objectType) 
    { 

     return typeof(Type).IsAssignableFrom(objectType); 
    } 
} 

I jest jeszcze jeden, który serializes rzeczywistej wartości ENUM:

public class EnumValueConverter : JsonConverter 
{ 
    public override void WriteJson(
     JsonWriter writer, 
     object value, 
     JsonSerializer serializer) 
    { 
     if (value == null) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     EnumValue result = EnumHelpers.GetEnumValue(value, value.GetType()); 

     serializer.Serialize(writer, result); 
    } 

    public override object ReadJson(
     JsonReader reader, 
     Type objectType, 
     object existingValue, 
     JsonSerializer serializer) 
    { 
     throw new NotSupportedException(); 
    } 

    public override bool CanRead { get { return false; } } 

    public override bool CanConvert(Type objectType) 
    { 

     return objectType.IsEnum; 
    } 
} 

Oto jak można wykorzystać to wszystko:

var pr = new ProjectDto(); 
pr.CurrentStatus = Status.Active; 
pr.StatusEnum = typeof(Status); 

var settings = new JsonSerializerSettings(); 
settings.Converters = new JsonConverter[] 
{ 
    new EnumTypeConverter(), 
    new EnumValueConverter() 
}; 
settings.Formatting = Newtonsoft.Json.Formatting.Indented; 

string serialized = JsonConvert.SerializeObject(pr, settings); 

Przykład:https://dotnetfiddle.net/BVp7a2

+0

Dzięki kolego, tego właśnie szukałem! Jakąkolwiek sugestię, dlaczego linie przerwań uzyskują \ r \ n? –

+2

@ArneHB: Masz na myśli wygenerowany JSON lub wartości w obrębie nieruchomości? Możesz usunąć podziały wierszy, usuwając opcję formatowania z wcięciem. –

+0

@AndrewWhitetaker Przykro mi, mój kolego, byłem nieco zbyt szczęśliwy z powodu komentarza, zanim zdałem sobie sprawę, że próbowałem serializować go dwa razy. Dzięki za pomoc, jej czyste i przyjemne rozwiązanie! Przeniosłem Konwertery, więc teraz działa globalnie na wszystkich seriach JSON –