JSON.NET序列化空JSON

时间:2017-07-11 22:37:38

标签: c# json serialization json.net

我正在使用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,我将MemberSerialization更改为OptIn而不是OptOut,因为我想要包含的属性少于遗漏。

1 个答案:

答案 0 :(得分:5)

如Newtonsoft在this issue中所述,MetadataTypeAttribute属性实际上是由Json.NET支持的。但是,似乎Json.NET要求MetadataClassType成员必须是相应的&#34; real&#34;成员是属性,而对应的&#34;真实&#34;成员是领域。因此,如果我按如下方式定义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 Fiddle #2显示此行为。这可能是牛顿问题;如Microsoft文档Defining Attributes in Metadata Classes中所述:

  

这些属性的实际类型并不重要,会被忽略   由编译器。接受的方法是将它们全部声明为   输入Object。

如果重要,您可以report an issue关于Newtonsoft的退货类型限制 - 或者报告一个问题,询问他们对MetadataTypeAttribute的支持的详细信息是否有更完整的记录。