一尘不染

JSON.NET序列化空JSON

json

我正在使用MetadataType以下类型定义Json.NET属性,然后在其ToString()方法内部使用Json.NET对其进行序列化:

namespace ConsoleApp1
{
    public interface ICell
    {
        int Id { get; }
    }
    public interface IEukaryote
    {
        System.Collections.Generic.IEnumerable<ICell> Cells { get; }
        string GenericName { get; }
    }
    public sealed partial class PlantCell
        : ICell
    {
        public int Id => 12324;
    }
    public sealed partial class Plant
        : IEukaryote
    {
        private readonly System.Collections.Generic.IDictionary<string, object> _valuesDict;
        public Plant()
        {
            _valuesDict = new System.Collections.Generic.Dictionary<string, object>();
            var cells = new System.Collections.Generic.List<PlantCell>();
            cells.Add(new PlantCell());
            _valuesDict["Cells"] = cells;
            _valuesDict["GenericName"] = "HousePlant";
        }
        public System.Collections.Generic.IEnumerable<ICell> Cells => _valuesDict["Cells"] as System.Collections.Generic.IEnumerable<ICell>;
        public string GenericName => _valuesDict["GenericName"] as string;
        public int SomethingIDoNotWantSerialized => 99999;
        public override string ToString()
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(this,
                new Newtonsoft.Json.JsonSerializerSettings()
                {
                    ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
                }
            );
        }
    }
    [System.ComponentModel.DataAnnotations.MetadataType(typeof(PlantMetadata))]
    public sealed partial class Plant
    {
        [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)]
        internal sealed class PlantMetadata
        {
            [Newtonsoft.Json.JsonProperty]
            public System.Collections.Generic.IEnumerable<ICell> Cells;
            [Newtonsoft.Json.JsonProperty]
            public string GenericName;
            //...
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var plant = new Plant();
            System.Console.WriteLine(System.String.Format("Output is {0}", plant.ToString()));
            System.Console.ReadKey();
        }
    }
}

我的问题是,Plant.ToString()它将返回“
{}”。这是为什么?以前在工作。我所做的唯一更改是PlantMetadata更改了MemberSerializationOptIn而不是OptOut,因为我希望包含的属性少于保留的属性。


阅读 202

收藏
2020-07-27

共1个答案

一尘不染

如Newtonsoft在本期中所述MetadataTypeAttributeJson.NET实际上支持属性。但是,MetadataClassType当相应的“真实”成员是属性时,似乎Json.NET要求成员必须是属性,而当相应的“真实”成员是字段时,则要求字段是域。因此,如果我Plant按以下方式定义您的类型,并且具有两个属性和一个要序列化的字段:

public sealed partial class Plant : IEukaryote
{
    public System.Collections.Generic.IEnumerable<ICell> Cells { get { return (_valuesDict["Cells"] as System.Collections.IEnumerable).Cast<ICell>(); } }
    public string GenericName { get { return _valuesDict["GenericName"] as string; } }
    public string FieldIWantSerialized;
    public int SomethingIDoNotWantSerialized { get { return 99999; } }

    // Remainder as before.

然后,PlantMetadata必须还必须具有两个属性和一个字段才能成功序列化它们:

//Metadata.cs
[System.ComponentModel.DataAnnotations.MetadataType(typeof(PlantMetadata))]
public sealed partial class Plant
{
    [JsonObject(MemberSerialization.OptIn)]
    internal sealed class PlantMetadata
    {
        [JsonProperty]
        public IEnumerable<ICell> Cells { get; set; }

        [JsonProperty]
        public string GenericName { get; set; }

        [JsonProperty]
        public string FieldIWantSerialized;
    }
}

如果我创建CellsGenericName成为字段,或者FieldIWantSerialized成为属性,则它们不会选择序列化。

示例工作 .Net Fiddle

请注意,此外,我发现这些MetadataClassType属性显然必须具有与真实属性相同的 返回类型
。如果我将您的更改PlantMetadata如下:

[JsonObject(MemberSerialization.OptIn)]
internal sealed class PlantMetadata
{
    [JsonProperty]
    public object Cells { get; set; }

    [JsonProperty]
    public object GenericName { get; set; }

    [JsonProperty]
    public object FieldIWantSerialized;
}

然后仅FieldIWantSerialized序列化,不对属性进行序列化。
.Net小提琴#2显示此行为。这可能是Newtonsoft的问题;如Microsoft文档在元数据类中定义属性中所述

这些属性的实际类型并不重要,编译器将忽略它们。公认的方法是将它们全部声明为Object类型。

如果有问题,您可以向Newtonsoft
报告有关返回类型限制的问题-
或报告一个问题,要求对其支持的详细信息MetadataTypeAttribute进行更详细的记录。

2020-07-27