admin管理员组文章数量:1300174
In our C# application on .NET 4.8, we tried to use a PopulateObject
for deserializing data returned from an API. This API is not under our control.
Now the API developer added a new enum value and when we try to map it in our own Enum
it crashes with a message like
Error converting value 'x' to 'enum-y'
Now we COULD adjust our enum and go on, but that would only be a temporary fix until it happens again at another part of the code. We searched a little bit and found a specific solution. We added an 'Unknown' value to our enum and then added a converter like this:
public class AllowedMethodConverter : StringEnumConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
if (Enum.TryParse(reader.Value.ToString(), out Method result)) // Here the Method has to be known
return result;
else
return Method.Unknown;
}
return base.ReadJson(reader, objectType, existingValue, serializer);
}
}
[JsonConverter(typeof(AllowedMethodConverter))]
public enum Method
{
Unknown,
Method1,
Method2
}
This is used in a very simple API method where we get the string from the API and afterwards:
JsonConvert.PopulateObject(response.Content, userSettings);
That works fine so far, but this would require one StringEnumConverter
per enum. With roughly 40 enums, it would be a little bit much to create 40 converters, just so I can ignore some values that do not exist.
Does anyone have a better idea how to handle this?
In our C# application on .NET 4.8, we tried to use a PopulateObject
for deserializing data returned from an API. This API is not under our control.
Now the API developer added a new enum value and when we try to map it in our own Enum
it crashes with a message like
Error converting value 'x' to 'enum-y'
Now we COULD adjust our enum and go on, but that would only be a temporary fix until it happens again at another part of the code. We searched a little bit and found a specific solution. We added an 'Unknown' value to our enum and then added a converter like this:
public class AllowedMethodConverter : StringEnumConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
if (Enum.TryParse(reader.Value.ToString(), out Method result)) // Here the Method has to be known
return result;
else
return Method.Unknown;
}
return base.ReadJson(reader, objectType, existingValue, serializer);
}
}
[JsonConverter(typeof(AllowedMethodConverter))]
public enum Method
{
Unknown,
Method1,
Method2
}
This is used in a very simple API method where we get the string from the API and afterwards:
JsonConvert.PopulateObject(response.Content, userSettings);
That works fine so far, but this would require one StringEnumConverter
per enum. With roughly 40 enums, it would be a little bit much to create 40 converters, just so I can ignore some values that do not exist.
Does anyone have a better idea how to handle this?
Share edited Feb 11 at 15:48 marc_s 755k184 gold badges1.4k silver badges1.5k bronze badges asked Feb 11 at 13:40 Marcel GrügerMarcel Grüger 9441 gold badge11 silver badges26 bronze badges 2- "He added a new 'breaking' enum". Not sure why "adding" should break things; the API to enums is their "names" ... across applications. You've established your "working set"; if "additions" are not relevant you ignore them (like "options"). If they imply logic changes, how else are you going to stay aware? – Gerry Schmitz Commented Feb 11 at 19:49
- Adding a new validation method that we don't implement is one thing, but giving us the info that they provide method-x and my application crashes just out of getting this info, that would be really a bad design. – Marcel Grüger Commented Feb 12 at 7:35
1 Answer
Reset to default 1I created a simple solution to handle those pesky API enum changes without crashing your app.
Instead of writing 40 different converters (yikes!), I made a single, smart converter that works with all your enums. When the API throws a new value at you, it just returns "Unknown" instead of breaking everything - no more emergency fixes needed!
Just add the Unknown value to your enum, slap on the converter attribute, and you're good to go. Super easy to plug into your existing code, and it'll save you tons of headaches down the road.
using Newtonsoft.Json;
using System;
// Interface to mark enums that should handle unknown values
public interface IUnknownValueEnum
{
bool IsUnknown { get; }
}
// Generic converter that can handle any enum implementing IUnknownValueEnum
public class UnknownValueEnumConverter<T> : JsonConverter<T> where T : Enum
{
public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
string enumString = reader.Value?.ToString();
// Try to parse the enum value
if (!string.IsNullOrEmpty(enumString) && Enum.TryParse(enumString, true, out T result))
{
return result;
}
// If parsing fails, return the Unknown value
foreach (T value in Enum.GetValues(typeof(T)))
{
if (value is IUnknownValueEnum unknownEnum && unknownEnum.IsUnknown)
{
return value;
}
}
}
// If no Unknown value is found, throw exception
throw new JsonSerializationException($"Cannot convert value to enum {typeof(T).Name}");
}
public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
}
// Base class for enums that need unknown value handling
public abstract class UnknownValueEnumBase : IUnknownValueEnum
{
public bool IsUnknown => this.ToString().Equals("Unknown", StringComparison.OrdinalIgnoreCase);
}
// Example usage:
[JsonConverter(typeof(UnknownValueEnumConverter<Method>))]
public enum Method : int
{
Unknown = 0,
Method1 = 1,
Method2 = 2
}
// Implementation for the enum
public partial class Method : UnknownValueEnumBase { }
// Example class using the enum
public class Settings
{
public Method AllowedMethod { get; set; }
}
// Usage example:
public class Example
{
public void DeserializeExample()
{
string json = @"{ ""AllowedMethod"": ""NewMethodAddedByAPI"" }";
var settings = JsonConvert.DeserializeObject<Settings>(json);
// settings.AllowedMethod will be Method.Unknown
}
}
本文标签: cPopulating enums without exceptionStack Overflow
版权声明:本文标题:c# - Populating enums without exception - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741660248a2390993.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论