我正在使用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,因为我想要包含的属性少于遗漏。
答案 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;
}
}
如果我将Cells
或GenericName
设为字段,或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
的支持的详细信息是否有更完整的记录。