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