wake-up-neo.net

So dekorieren Sie JSON.NET StringEnumConverter

Ich verbrauche eine API, die solche String-Werte zurückgibt. some-enum-value

Ich versuche, diese Werte in eine Aufzählung zu setzen, da der Standard-StringEnumConverter nicht die Aufgabe erfüllt, diesen Konverter mit zusätzlicher Logik zu dekorieren. Wie kann ich sicherstellen, dass die Werte korrekt deserialisiert werden?

Der folgende Code ist mein Tryout, um diese Arbeit zu erledigen. Die Zeile reader = new JsonTextReader(new StringReader(cleaned)); bricht jedoch das Ganze, da base.ReadJson die Zeichenfolge nicht als JSON erkennen kann.

Gibt es eine bessere Möglichkeit, dies zu tun, ohne die vorhandene Logik in StringEnumConverter implementieren zu müssen? Wie kann ich meinen Ansatz korrigieren?

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));
    }
}
25
Marco Franssen

Ich habe das Problem gelöst, indem ich den EnumMember-Attributen EnumMember-Attribute hinzugefügt habe. Der Json.NET-Standard StringEnumConverter behandelt diese Attribute perfekt.

Beispiel:

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

Bitte beachten Sie, dass Sie die Attribute nur für Bindestriche oder andere Sonderzeichen angeben müssen, die Sie nicht in Ihrer Enumeration verwenden können. Die Großbuchstaben werden von StringEnumConverter behandelt. Wenn der Dienst also einen Wert wie someenumvalue zurückgibt, sollten Sie ihn in der Aufzählung Someenumvalue so verwenden. Wenn Sie SomeEnumValue bevorzugen, sollten Sie das EnumMember-Attribut verwenden. Wenn der Dienst es so zurückgibt, someEnumValue, können Sie es einfach so verwenden: SomeEnumValue (Dies funktioniert sofort, wenn Sie die CamelCaseText-Eigenschaft verwenden. 

Sie können Ihre Konverter und andere Einstellungen einfach in JsonSerializerSettings angeben.

Hier ist ein Beispiel für die Einstellungen, die ich selbst verwende.

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

Sie können diesen Code auch verwenden:

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

Bei der Serialisierung von JsonConvert.Serialize() wird der Text in der EnumMember verwendet.

21
A-Sharabiani

Dies wurde in Json.NET 12.0.1 durch Hinzufügen von NamingStrategy zu StringEnumConverter vereinfacht:

Neue Funktion - Unterstützung für NamingStrategy zu StringEnumConverter hinzugefügt

Da in Json.NET keine dash case naming-Strategie eingebaut ist, definieren Sie eine wie folgt durch Unterklasse SnakeCaseNamingStrategy :

public class DashCaseNamingStrategy : SnakeCaseNamingStrategy
{
    protected override string ResolvePropertyName(string name)
    {
        return base.ResolvePropertyName(name).Replace('_', '-');
    }
}

Jetzt können Sie es in einen der mehreren Konstruktoren für StringEnumConverter übergeben, wenn Sie Konverter erstellen und zu JsonSerializerSettings.Converters hinzufügen:

var settings = new JsonSerializerSettings
{
    Converters = { new StringEnumConverter(typeof(DashCaseNamingStrategy)) },
};
var json = JsonConvert.SerializeObject(MyEnum.SomeEnumValue, settings);

Assert.IsTrue(json == "\"some-enum-value\""); // Passes successfully

Bei MyEnum sind bei diesem Ansatz überhaupt keine Anmerkungen erforderlich.

0
dbc

Sie können auch diese Methoden verwenden:

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

oder

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

und enum sollte das Attribut description haben. So was: 

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

    }

Und dann kannst du deine enum so verwenden:

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