// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Reflection;
using Xunit;
namespace System.Text.Json.Serialization.Tests
Assert.Equal(@"""?""", JsonSerializer.Serialize(value, options));
}
}
+
+ // A custom enum converter that uses an array for containing bit flags.
+ private sealed class JsonStringEnumArrayConverter : JsonConverterFactory
+ {
+ public JsonStringEnumArrayConverter() { }
+
+ public override bool CanConvert(Type typeToConvert)
+ {
+ return typeToConvert.IsEnum;
+ }
+
+ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ {
+ JsonConverter converter = (JsonConverter)Activator.CreateInstance(
+ typeof(JsonConverterEnumArray<>).MakeGenericType(typeToConvert),
+ BindingFlags.Instance | BindingFlags.Public,
+ binder: null,
+ args: null,
+ culture: null);
+
+ return converter;
+ }
+ }
+
+ internal class JsonConverterEnumArray<T> : JsonConverter<T>
+ where T : struct, Enum
+ {
+ public override bool CanConvert(Type type)
+ {
+ return type.IsEnum;
+ }
+
+ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType != JsonTokenType.StartArray)
+ {
+ throw new JsonException();
+ }
+
+ string enumString = default;
+
+ bool first = true;
+ while (true)
+ {
+ reader.Read();
+
+ if (reader.TokenType == JsonTokenType.EndArray)
+ {
+ break;
+ }
+
+ if (reader.TokenType != JsonTokenType.String)
+ {
+ throw new JsonException();
+ }
+
+ string enumValue = reader.GetString();
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ enumString += ",";
+ }
+
+ enumString += enumValue.ToString();
+ }
+
+ if (!Enum.TryParse(enumString, out T value))
+ {
+ throw new JsonException();
+ }
+
+ return value;
+ }
+
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ string[] enumString = value.ToString().Split(',');
+
+ writer.WriteStartArray();
+
+ foreach (string enumValue in enumString)
+ {
+ writer.WriteStringValue(enumValue.TrimStart());
+ }
+
+ writer.WriteEndArray();
+ }
+ }
+
+ [Flags]
+ [JsonConverter(typeof(JsonStringEnumArrayConverter))]
+ public enum eDevice : uint
+ {
+ Unknown = 0x0,
+ Phone = 0x1,
+ PC = 0x2,
+ Laptop = 0x4,
+ Tablet = 0x8,
+ IoT = 0x10,
+ Watch = 0x20,
+ TV = 0x40,
+ Hub = 0x80,
+ Studio = 0x100,
+ Book = 0x200,
+ MediaCenter = 0x400,
+ }
+
+ [Theory]
+ [InlineData(@"[""PC"",""Tablet""]")]
+ [InlineData(@"[""Tablet"",""PC""]")]
+ public static void EnumValue(string json)
+ {
+ eDevice obj;
+
+ void Verify()
+ {
+ Assert.Equal(eDevice.PC | eDevice.Tablet, obj);
+ }
+
+ obj = JsonSerializer.Deserialize<eDevice>(json);
+ Verify();
+
+ // Round-trip and verify.
+ json = JsonSerializer.Serialize(obj);
+ obj = JsonSerializer.Deserialize<eDevice>(json);
+ Verify();
+ }
+
+ private class ConnectionList
+ {
+ public List<ConnectionFile> Connections { get; set; }
+ }
+
+ private class ConnectionFile
+ {
+ public eDevice Device { get; set; }
+ }
+
+ [Theory]
+ [InlineData(@"{""Connections"":[{""Device"":[""PC"",""Tablet""]},{""Device"":[""PC"",""Laptop""]}]}")]
+ [InlineData(@"{""Connections"":[{""Device"":[""Tablet"",""PC""]},{""Device"":[""Laptop"",""PC""]}]}")]
+ public static void EnumArray(string json)
+ {
+ ConnectionList obj;
+
+ void Verify()
+ {
+ Assert.Equal(2, obj.Connections.Count);
+ Assert.Equal(eDevice.PC | eDevice.Tablet, obj.Connections[0].Device);
+ Assert.Equal(eDevice.PC | eDevice.Laptop, obj.Connections[1].Device);
+ }
+
+ obj = JsonSerializer.Deserialize<ConnectionList>(json);
+ Verify();
+
+ // Round-trip and verify.
+ json = JsonSerializer.Serialize(obj);
+ obj = JsonSerializer.Deserialize<ConnectionList>(json);
+ Verify();
+ }
}
}