我可以使用 System.Text.Json 通过私有构造函数反序列化 Json 吗?

smi*_*rth 17 c# .net-core system.text.json

想知道是否可以拥有私有构造函数并使用新的 System.Text.Json 序列化器。

public class MyModel
{
    public string Name { get; set; }
    public string Data { get; set; }

    private MyModel() 
    {
        // use me for when deserializing
    }

    public MyModel(string name, string data)
    {
        Name = name;
        Data = data;
    }
}
Run Code Online (Sandbox Code Playgroud)

简单的往返。

var model = new MyModel("doo", "doo");
var json = JsonSerializer.Serialize(model, new JsonSerializerOptions
{
    WriteIndented = true
});

// no to go because of there is no parameterless constructor defined for this object.
var rehydrated = JsonSerializer.Deserialize<MyModel>(json);
Run Code Online (Sandbox Code Playgroud)

Tan*_*jel 21

.NET 8.0 中的更新

只需添加JsonConstructorAttribute到私有构造函数中,如下所示:

public class Employee
{
   [JsonConstructor] // This will work from .NET 8.0
   private Employee()
   {
   }

   private Employee(int id, string name)
   {
     Id = id;
     Name = name;
   }

   [JsonInclude]
   public int Id { get; private set; }

   [JsonInclude]
   public string Name { get; private set; }

   public static Employee Create(int id, string name)
   {
     Employee employee = new Employee(id, name);
     return employee;
   }
}

Run Code Online (Sandbox Code Playgroud)

.NET 7.0 中的更新

从 .NET 7.0 开始,可以通过编写自己的 ContractResolver 使用私有无参数构造函数来完成反序列化,如下所示:

public class PrivateConstructorContractResolver : DefaultJsonTypeInfoResolver
{
   public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
   {
       JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);

       if (jsonTypeInfo.Kind == JsonTypeInfoKind.Object && jsonTypeInfo.CreateObject is null)
       {
         if (jsonTypeInfo.Type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Length == 0)
         {
            // The type doesn't have public constructors
            jsonTypeInfo.CreateObject = () => 
                Activator.CreateInstance(jsonTypeInfo.Type, true);
         }
       }

      return jsonTypeInfo;
   }
}
Run Code Online (Sandbox Code Playgroud)

使用方法如下:

private static void Main(string[] args)
{
    JsonSerializerOptions options = new JsonSerializerOptions
    {
       TypeInfoResolver = new PrivateConstructorContractResolver()
    };

    Employee employee = Employee.Create(1, "Tanvir");
    string jsonString = JsonSerializer.Serialize(employee);
    Employee employee1 = JsonSerializer.Deserialize<Employee>(jsonString , options);
}

public class Employee
{
   private Employee()
   {
   }

   private Employee(int id, string name)
   {
     Id = id;
     Name = name;
   }

   [JsonInclude]
   public int Id { get; private set; }

   [JsonInclude]
   public string Name { get; private set; }

   public static Employee Create(int id, string name)
   {
     Employee employee = new Employee(id, name);
     return employee;
   }
}
Run Code Online (Sandbox Code Playgroud)


S'p*_*'Kr 5

答案似乎是“否”,或者至少是“还没有”

这是[System.Text.Json] v1的 System.Text.Json 序列化程序的已知限制。我们计划将来支持这一点。 -阿松汗

您可以为此编写一个自定义转换器...对于[ASP.NET Core] 3.0 版本,没有计划在反序列化期间调用非默认构造函数的额外支持。这必须由定制转换器来完成。——史蒂夫哈特

链接的自定义转换器选项将允许您使用您拥有的任何 API 来构建对象,但与 Newtonsoft.Json 或实体框架通过摆弄反射和私有构造函数可以完成的操作不同,所以可能不是你在寻找什么。

  • 是否有任何为所有构造函数都是私有的类实现自定义转换器的示例? (3认同)