Hi folks,
I'm trying to deseralize an array of values of an enum but I can not get array values in JsonConverter. These are my questions:
Cheers
{
"Connections": [
{
"Device": [ 2, 8 ]
},
{
"Device": [ 2, 4 ]
}
]
}
```c#
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("connexions.json");
var entry = JsonSerializer.Deserialize
}
internal sealed class ConnectionList
{
[JsonPropertyName("Connections")]
public List<ConnectionFile> Connections { get; set; }
}
public sealed class ConnectionFile
{
//[JsonPropertyName("Device")]
public eDevice Device { get; set; }
}
[Flags]
[JsonConverter(typeof(JsonToEnumDeviceConverter))]
public enum eDevice : uint
{
Unknown = 0,
Phone = 1,
PC = 2,
Laptop = 4,
Tablet = 8,
IoT = 16,
Watch = 32,
TV = 64,
Hub = 128,
Studio = 256,
Book = 512,
MediaCenter = 1024
}
internal sealed class JsonToEnumDeviceConverter : JsonConverter<eDevice>
{
public override eDevice Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.StartArray:
/* Json.net equivalent (with string values)
JToken token = JToken.Load(reader);
List<string> items = token.ToObject<List<string>>();
*/
break;
}
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, eDevice value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
}
````
Isn't this supported with JsonStringEnumConverter? What happens when you use this built-in converter in the JsonConverterAttribute instead of your own?
@Joelius300
I'm using 4.6.0-preview8.19405.3.
According https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/src/System/Text/Json/Serialization/JsonStringEnumConverter.cs this class should be in System.Text.Json.Serialization but it is missing:

Cheers
It's there, it just doesn't show because it isn't an attribute. You have to use that converter as the type in the JsonConverterAttribute.
Try this:
[JsonConverter(typeof(JsonStringEnumConverter))]
@Joelius300,
Test 1 : Failing
System.Text.Json.JsonException: 'The JSON value could not be converted to ConsoleCore.Program+eDevice. Path: $.Connections[0].Device | LineNumber: 3 | BytePositionInLine: 17.'
`
static void Main(string[] args)
{
string json = File.ReadAllText("connexions.json");
var entry = JsonSerializer.Deserialize
}
internal sealed class ConnectionList
{
[JsonPropertyName("Connections")]
public List<ConnectionFile> Connections { get; set; }
}
public sealed class ConnectionFile
{
[JsonPropertyName("Device")]
public eDevice Device { get; set; }
}
[Flags]
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum eDevice : uint
{
Unknown = 0,
Phone = 1,
PC = 2,
Laptop = 4,
Tablet = 8,
IoT = 16,
Watch = 32,
TV = 64,
Hub = 128,
Studio = 256,
Book = 512,
MediaCenter = 1024
}
}
`
Test 2 : Failing
System.Text.Json.JsonException: 'The JSON value could not be converted to ConsoleCore.Program+eDevice. Path: $.Connections[0].Device | LineNumber: 3 | BytePositionInLine: 17.'
{
"Connections": [
{
"Device": [ "PC", "Tablet" ]
},
{
"Device": [ "PC", "Laptop" ]
}
]
}
Json.net: using a converter I can return PC | Tablet | ... into Device property. This is the code I'm using;
`
using Newtonsoft.Json;
public class JsonFlagConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.StartArray:
{
JToken token = JToken.Load(reader);
List<string> items = token.ToObject<List<string>>();
List<ulong> converted = new List<UInt64>();
Type t = objectType.GetEnumUnderlyingType();
if (t == typeof(Int16))
converted = FromInt16(items, objectType);
else if (t == typeof(Int32))
converted = FromInt32(items, objectType);
else if (t == typeof(Int64))
converted = FromInt64(items, objectType);
else if (t == typeof(Byte))
converted = FromByte(items, objectType);
else if (t == typeof(UInt16))
converted = FromUInt16(items, objectType);
else if (t == typeof(UInt32))
converted = FromUInt32(items, objectType);
else if (t == typeof(UInt64))
converted = FromUInt64(items, objectType);
else
throw new NotImplementedException("Undefined conversor type " + t.FullName);
UInt64 sum = 0;
foreach (ulong n in converted)
{
if (sum == 0)
sum = n;
else
sum = sum | n;
}
return Enum.ToObject(objectType, sum);
}
default:
throw new NotImplementedException(reader.TokenType.ToString());
}
}
private List<UInt64> FromByte(List<string> items, Type objectType)
{
List<byte> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<Byte>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromInt16(List<string> items, Type objectType)
{
List<short> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<Int16>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromInt32(List<string> items, Type objectType)
{
List<int> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<Int32>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromInt64(List<string> items, Type objectType)
{
List<long> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<Int64>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromUInt16(List<string> items, Type objectType)
{
List<ushort> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<UInt16>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromUInt32(List<string> items, Type objectType)
{
List<uint> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<UInt32>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
private List<UInt64> FromUInt64(List<string> items, Type objectType)
{
List<ulong> e_items = items.Select(x => Enum.Parse(objectType, x)).Cast<UInt64>().ToList();
return e_items.ConvertAll(i => (UInt64)i);
}
public override void WriteJson(JsonWriter writer, Object value, JsonSerializer serializer)
{
//https://stackoverflow.com/questions/43143175/c-sharp-json-net-render-flags-enum-as-string-array?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
IEnumerable<string> flags = value.ToString()
.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
.Select(f => $"\"{f}\"");
writer.WriteRawValue($"[{string.Join(", ", flags)}]");
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
`
Looks to me like this sample is representing a flags enum as either an array of ints ("Device": [ 2, 8 ]) or array of enum string values ("Device": [ "PC", "Tablet" ]). @steveharter do we have a built in converter for that, or is a custom converter required? /cc @ahsonkhan
There is not a built-in converter to treat a flags enum as an array.
Changing the json from
@"{""Connections"": [{""Device"":[""PC"",""Tablet""]},{""Device"":[""PC"",""Laptop""]}]}"
to
@"{""Connections"": [{""Device"":""PC,Tablet""},{""Device"":""PC,Laptop""}]}"
works as expected.
I'll work on an example of a custom converter that uses an array.
Thanks a lot @steveharter. Your solutions works.
Most helpful comment
There is not a built-in converter to treat a flags enum as an array.
Changing the json from
@"{""Connections"": [{""Device"":[""PC"",""Tablet""]},{""Device"":[""PC"",""Laptop""]}]}"to
@"{""Connections"": [{""Device"":""PC,Tablet""},{""Device"":""PC,Laptop""}]}"works as expected.
I'll work on an example of a custom converter that uses an array.