C# 如何从JsonConvert.PopulateObject中排除不带';不存在于某些基类型或接口中?

C# 如何从JsonConvert.PopulateObject中排除不带';不存在于某些基类型或接口中?,c#,serialization,interface,json.net,populate,C#,Serialization,Interface,Json.net,Populate,是否可以为JsonConvert.PopulateObject定义选项,以排除目标对象接口实现中不存在的json中给定的字段 public interface IElementWriter { string Name { get; set; } } public interface IElementUpdateWriter : IElementWriter { string FirstName { get; set; } } public interface IElementIn

是否可以为JsonConvert.PopulateObject定义选项,以排除目标对象接口实现中不存在的json中给定的字段

public interface IElementWriter
{
    string Name { get; set; }
}
public interface IElementUpdateWriter : IElementWriter
{
    string FirstName { get; set; }
}
public interface IElementInsertWriter : IElementWriter
{
    DateTime? CreationDate { get; set; }
}

public class Element:IElementWriter, IElementInsertWriter, IElementUpdateWriter {
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime? CreationDate { get; set; }
    public string FirstName { get; set; }
}

static void Main(string[] args)
{
    IElementWriter element = new Element() { ID = 1, Name = "SourceName", CreationDate=DateTime.Today, FirstName="SourceFirstName" };

    string json = "{ id:'8', Name:'newName', FirstName:'newFirstName' }";

    JsonConvert.PopulateObject(json, element, new JsonSerializerSettings() {

    });
    Console.WriteLine(JsonConvert.SerializeObject(element));
    Console.ReadLine();
}
结果

{“ID”:8,“Name”:“newName”,“CreationDate”:“2019-06-05T00:00:00+02:00”,“FirstName”:“newFirstName”}

必需,因为IElementWriter既没有ID也没有名字:

{“ID”:1,“Name”:“newName”,“CreationDate”:“2019-06-05T00:00:00+02:00”,“FirstName”:“SourceFirstName”}


JsonSerializerSettings
中没有简单的设置会导致像填充某个基类型的实例一样填充派生类型的实例。要确认这一点,您可以检查源,它只将
读取器
目标
作为参数,并直接从其类型中提取目标的:

public void Populate(JsonReader reader, object target)
{
    Type objectType = target.GetType();

    JsonContract contract = Serializer._contractResolver.ResolveContract(objectType);
因此,您的选择包括:

  • 修改
    元素
    类的定义,并将
    [JsonIgnore]
    添加到不希望填充的属性中

    您可能不想这样做,因为这样会阻止对属性进行序列化或反序列化

  • 使用a忽略
    元素
    的所有属性,这些属性不是
    IElementWriter
    的属性

    这似乎是更好的解决办法

  • 假设您选择选项#2,您可以引入以下自定义合同解析器:

    public class UpcastingContractResolver<TDerived, TBase> : DefaultContractResolver where TDerived: TBase
    {
        readonly HashSet<string> baseProperties = ((JsonObjectContract)JsonSerializer.Create().ContractResolver.ResolveContract(typeof(TBase)))
            .Properties.Select(p => p.UnderlyingName)
            .ToHashSet();
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = base.CreateProperties(type, memberSerialization);
            if (type == typeof(TDerived) || type.IsSubclassOf(typeof(TDerived)))
            {
                foreach (var property in properties)
                {
                    if (!baseProperties.Contains(property.UnderlyingName))
                        property.Ignored = true;
                }
            }
            return properties;
        }
    }
    

    演示小提琴。

    JsonSerializerSettings
    中没有简单的设置会导致填充派生类型的实例,就像它是某个基类型的实例一样。要确认这一点,您可以检查源,它只将
    读取器
    目标
    作为参数,并直接从其类型中提取目标的:

    public void Populate(JsonReader reader, object target)
    {
        Type objectType = target.GetType();
    
        JsonContract contract = Serializer._contractResolver.ResolveContract(objectType);
    
    因此,您的选择包括:

  • 修改
    元素
    类的定义,并将
    [JsonIgnore]
    添加到不希望填充的属性中

    您可能不想这样做,因为这样会阻止对属性进行序列化或反序列化

  • 使用a忽略
    元素
    的所有属性,这些属性不是
    IElementWriter
    的属性

    这似乎是更好的解决办法

  • 假设您选择选项#2,您可以引入以下自定义合同解析器:

    public class UpcastingContractResolver<TDerived, TBase> : DefaultContractResolver where TDerived: TBase
    {
        readonly HashSet<string> baseProperties = ((JsonObjectContract)JsonSerializer.Create().ContractResolver.ResolveContract(typeof(TBase)))
            .Properties.Select(p => p.UnderlyingName)
            .ToHashSet();
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = base.CreateProperties(type, memberSerialization);
            if (type == typeof(TDerived) || type.IsSubclassOf(typeof(TDerived)))
            {
                foreach (var property in properties)
                {
                    if (!baseProperties.Contains(property.UnderlyingName))
                        property.Ignored = true;
                }
            }
            return properties;
        }
    }
    

    演示小提琴。

    没有任何设置可以做到这一点,您需要向
    元素
    类型添加属性(您可能不想这样做)或使用。想要后者的例子吗?没有任何设置可以做到这一点,您需要向
    元素
    类型添加属性(您可能不想这样做)或使用。想要后者的例子吗?谢谢。我接受“原样”,谢谢你。我认为这是“事实”。