یک نکتهی تکمیلی: نوشتن تبدیلگرهای نوعها برای System.Text.Json
System.Text.Json، در حال حاضر از مفهومی به نام type coercion/inference، پشتیبانی نمیکند. type coercion یعنی تبدیل یک مقدار، به مقداری دیگر که به صورت مستقیم قابل انتساب به یکدیگر نیستند. برای مثال اگر رشتهی "true" را درنظر بگیریم، قابلیت انتساب به یک خاصیت از نوع bool را ندارد. برای یک چنین مواردی در این API جدید، باید تبدیلگر نوشت.
یک مثال:
در این مثال، خاصیت IsInStock از نوع bool است، اما مقداری را که باید از طریق متد Deserialize دریافت کنیم، یک رشتهی bool ای است که قابل انتساب به bool نیست. در این حالت اگر برنامه را اجرا کنیم به استثنای زیر خواهیم رسید:
برای رفع این مشکل، میتوان تبدیلگر زیر را تدارک دید:
برای نوشتن یک تبدیلگر bool، کلاس مرتبط، باید <JsonConverter<bool را پیاده سازی کند. کلاس JsonConverter نیز به صورت زیر تعریف شدهاست:
و پیاده سازی دو متد Read و Write آن الزامی است.
در متد Read آن، مقدار رشتهای دریافت شدهی از منبع داده، در اختیار ما قرار میگیرد. سپس باید بر اساس این مقدار، مقدار متناظری را از نوع T که در اینجا bool است، بازگشت دهیم. برای مثال اگر یکی از مقادیر رشتهای true ،yes و 1 را دریافت کردیم، بجای آن true را بازگشت میدهیم.
اکنون برای استفادهی از آن خواهیم داشت:
و یا روش دیگر انجام اینکار، استفاده از ویژگی JsonConverter، برای معرفی تبدیلگر تهیه شدهاست:
از این تبدیلگر برای حالت Serialize نیز میتوان استفاده کرد:
System.Text.Json، در حال حاضر از مفهومی به نام type coercion/inference، پشتیبانی نمیکند. type coercion یعنی تبدیل یک مقدار، به مقداری دیگر که به صورت مستقیم قابل انتساب به یکدیگر نیستند. برای مثال اگر رشتهی "true" را درنظر بگیریم، قابلیت انتساب به یک خاصیت از نوع bool را ندارد. برای یک چنین مواردی در این API جدید، باید تبدیلگر نوشت.
یک مثال:
using System.Collections.Generic; using System.Text.Json; namespace JsonTests { public class Product { public int Id { get; set; } public string Name { get; set; } public bool IsInStock { get; set; } } class Program { static void Main(string[] args) { var products = JsonSerializer.Deserialize<List<Product>>("[{\"Id\":1026,\"Name\":\"P1\",\"IsInStock\":\"false\"}]"); } } }
An unhandled exception of type 'System.Text.Json.JsonException' occurred in System.Text.Json.dll Inner exceptions found, see $exception in variables window for more details. Innermost exception System.InvalidOperationException : Cannot get the value of a token type 'String' as a boolean.
public class BooleanConverter : JsonConverter<bool> { public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); if (value.Equals("true", StringComparison.OrdinalIgnoreCase) || value.Equals("yes", StringComparison.OrdinalIgnoreCase) || value.Equals("1", StringComparison.Ordinal)) { return true; } if (value.Equals("false", StringComparison.OrdinalIgnoreCase) || value.Equals("no", StringComparison.OrdinalIgnoreCase) || value.Equals("0", StringComparison.Ordinal)) { return false; } throw new NotSupportedException($"`{value}` can't be converted to `bool`."); } public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) { switch (value) { case true: writer.WriteStringValue("true"); break; case false: writer.WriteStringValue("false"); break; } } }
public abstract class JsonConverter<T> : JsonConverter { protected internal JsonConverter(); public override bool CanConvert(Type typeToConvert); public abstract T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options); public abstract void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options); }
در متد Read آن، مقدار رشتهای دریافت شدهی از منبع داده، در اختیار ما قرار میگیرد. سپس باید بر اساس این مقدار، مقدار متناظری را از نوع T که در اینجا bool است، بازگشت دهیم. برای مثال اگر یکی از مقادیر رشتهای true ،yes و 1 را دریافت کردیم، بجای آن true را بازگشت میدهیم.
اکنون برای استفادهی از آن خواهیم داشت:
var options = new JsonSerializerOptions(); options.Converters.Add(new BooleanConverter()); var products = JsonSerializer.Deserialize<List<Product>>( "[{\"Id\":1026,\"Name\":\"P1\",\"IsInStock\":\"false\"}]", options);
[JsonConverter(typeof(BooleanConverter))] public bool IsInStock { get; set; }
از این تبدیلگر برای حالت Serialize نیز میتوان استفاده کرد:
var options = new JsonSerializerOptions() {WriteIndented = true }; options.Converters.Add(new BooleanConverter()); var data = JsonSerializer.Serialize<List<Product>>(productList, options);