JSON.NET序列化空JSON

4

我使用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
复制并粘贴到新的VS项目中。 - Daniel L.
顺便提一下:使用OptOut的默认设置,然后向我不想序列化的属性添加JsonIgnore属性,将导致这些属性被序列化。 - Daniel L.
1个回答

5
根据 Newtonsoft 在此问题中所述,Json.NET 实际上支持 MetadataTypeAttribute 属性。然而,Json.NET 要求当相应的“真实”成员是属性时,MetadataClassType 成员必须是属性;当相应的“真实”成员是字段时,它们必须是字段。因此,如果我如下定义您的 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中展示了这种行为。可能是Newtonsoft的一个问题;正如Microsoft文档“在元数据类中定义属性”所述:
引用: 这些属性的实际类型并不重要,并且编译器会忽略它们。 接受的方法是将它们全部声明为Object类型。
如果需要的话,您可以向Newtonsoft报告问题-或者报告一个问题,请求更全面地记录他们对MetadataTypeAttribute的支持细节。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接