2014-04-07 14 views
16

Sto consumando un'API che restituisce valori di stringa come questo. some-enum-valueCome decorare JSON.NET StringEnumConverter

Io cerco di mettere questi valori in un enum, dal momento che il default StringEnumConverter non fare il lavoro cerco di decorare questo convertitore con una certa logica aggiuntiva. Come posso assicurarmi che i valori siano correttamente deserializzati?

Il seguente codice è il mio tentativo di portare a termine questo lavoro. Tuttavia la riga reader = new JsonTextReader(new StringReader(cleaned)); interrompe il tutto dal momento che la base non riesce a riconoscere la stringa come JSON.

Esiste un modo migliore per farlo senza dover implementare tutta la logica excisting in StringEnumConverter? Come risolvere il mio approccio?

public class BkStringEnumConverter : StringEnumConverter 
{ 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.String) 
     { 
      var enumString = reader.Value.ToString(); 
      if (enumString.Contains("-")) 
      { 
       var cleaned = enumString.Split('-').Select(FirstToUpper).Aggregate((a, b) => a + b); 
       reader = new JsonTextReader(new StringReader(cleaned)); 
      } 
     } 
     return base.ReadJson(reader, objectType, existingValue, serializer); 
    } 

    private static string FirstToUpper(string input) 
    { 
     var firstLetter = input.ToCharArray().First().ToString().ToUpper(); 
     return string.IsNullOrEmpty(input) 
      ? input 
      : firstLetter + string.Join("", input.ToCharArray().Skip(1)); 
    } 
} 

risposta

39

ho risolto il problema aggiungendo attributi EnumMember sui miei valori enum. L'impostazione predefinita Json.NET StringEnumConverter si adatta perfettamente a questi attributi.

Esempio:

public enum MyEnum 
{ 
    [EnumMember("some-enum-value")] 
    SomeEnumValue, 
    Value, 
    [EnumMember("some-other-value")] 
    SomeOtherValue 
} 

prega di notare che è sufficiente specificare gli attributi in caso di trattini o altri caratteri speciali non è possibile utilizzare nella vostra enum. La minuscola maiuscola viene gestita dallo StringEnumConverter. Quindi se il servizio restituisce un valore come someenumvalue, dovresti utilizzarlo in questo modo nell'enum Someenumvalue. Se si preferisce SomeEnumValue, è necessario utilizzare l'attributo EnumMember. Nel caso in cui il servizio lo restituisca come questo someEnumValue puoi semplicemente usarlo in questo modo SomeEnumValue (Funzionerà fuori dalla scatola quando usi la proprietà CamelCaseText).

È possibile specificare facilmente i convertitori e altre impostazioni nello JsonSerializerSettings.

Ecco un esempio delle impostazioni che uso io stesso.

new JsonSerializerSettings 
{ 
    ContractResolver = new CamelCasePropertyNamesContractResolver(), 
    Converters = new List<JsonConverter> { new StringEnumConverter { CamelCaseText = true } }, 
    NullValueHandling = NullValueHandling.Ignore 
}; 
+0

Ciao, ti preghiamo Potete fornire progetto di esempio perché non funziona per me. Grazie. –

+0

basta fornire JsonSerializerSettings al tuo JsonConverter –

+1

Piccolo commento. Se non si utilizza StringEnumConverter, ma il valore predefinito da json.net, l'enumMember non funzionerà. – dampee

11

È inoltre possibile utilizzare questo codice:

[JsonConverter(typeof(StringEnumConverter))] 
public enum ResposeStatus 
{ 
    [EnumMember(Value = "success value")] 
    Success, 
    [EnumMember(Value = "fail value")] 
    Fail, 
    [EnumMember(Value = "error value")] 
    Error 
}; 

durante la serializzazione JsonConvert.Serialize(), utilizzerà il testo all'interno della EnumMember.

+0

Sì, è possibile, ma come indicato nel mio ultimo commento sulla risposta accettata, è più semplice utilizzare serializeSettings. In questo modo non devi rovinare questi attributi dappertutto. –

0

anche u possibile utilizzare questi metodi:

public static string GetDescription(this Enum member) 
     { 
      if (member.GetType().IsEnum == false) 
       throw new ArgumentOutOfRangeException(nameof(member), "member is not enum"); 

      var fieldInfo = member.GetType().GetField(member.ToString()); 

      if (fieldInfo == null) 
       return null; 

      var attributes = fieldInfo.GetCustomAttributes<DescriptionAttribute>(false).ToList(); 

      return attributes.Any() ? attributes.FirstOrDefault()?.Description : member.ToString(); 
     } 

o

public static string GetDescription(this object member) 
     { 
      var type = member.GetType(); 

      var attributes = type.GetCustomAttributes<DescriptionAttribute>(false).ToList(); 

      return attributes.Any() ? attributes.FirstOrDefault()?.Description : member.GetType().Name; 
     } 

e enumerazione dovrebbe avere Desctription attributo. Come questo:

public enum MyEnum 
    { 
     [Description("some-enum-value")] 
     And, 
     [Description("some-enum-value")] 
     Or 

    } 

E quanto è possibile utilizzare il enum come questo:

MyEnum.GetDescription(); //return "some-enum-value"