C# 从Json.Net中的序列化中排除非自动属性

C# 从Json.Net中的序列化中排除非自动属性,c#,serialization,json.net,C#,Serialization,Json.net,我想序列化一组第三方结构,但它们有很多我不需要序列化的属性。我想从序列化中排除非自动属性(因为所有这些属性都不是自动的) 我怎样才能通过CustomContractResolver或其他方式做到这一点? 同时,我想包括私有字段的序列化 实现这一点的正确方法是什么?您可以通过编写自定义的JsonConverter来实现这一点。下面是一个示例(我尝试编写尽可能通用的自定义序列化程序,因此它应该适用于您的类型,而不做任何或细微的更改): 自定义类型和用法: [JsonConverter(typeof

我想序列化一组第三方结构,但它们有很多我不需要序列化的属性。我想从序列化中排除非自动属性(因为所有这些属性都不是自动的)

我怎样才能通过CustomContractResolver或其他方式做到这一点? 同时,我想包括私有字段的序列化


实现这一点的正确方法是什么?

您可以通过编写自定义的
JsonConverter
来实现这一点。下面是一个示例(我尝试编写尽可能通用的自定义序列化程序,因此它应该适用于您的类型,而不做任何或细微的更改):

自定义类型和用法:

[JsonConverter(typeof (CustomSerializer))]
public struct CustomStruct
{
    public int PublicInt;
    private int _privateInt;
    public string PublicString;
    private string _privateString;

    public int AutoInt { get; set; }
    public string AutoString { get; set; }

    public int ManualInt 
    {
        get{return _privateInt;}
        set { _privateInt = value; }
    }

    public string ManualString
    {
        get { return _privateString; }
        set { _privateString = value; }
    }
}

class Program
{
    private static void Main(string[] args)
    {
        var obj = new CustomStruct()
        {
            AutoInt = 10,
            AutoString = "autostring",
            ManualInt = 5,
            ManualString = "manualstring",
            PublicInt = 20,
            PublicString = "publicstring"
        };

        var json = JsonConvert.SerializeObject(obj,Formatting.Indented);

        var dObj = JsonConvert.DeserializeObject<CustomStruct>(json);
    }
}
public class CustomSerializer : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return typeof (CustomSerializer) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);

        var value = existingValue ?? Activator.CreateInstance(objectType);

        PopulateAutoProperties(objectType, jObject, value);
        PopulateFields(objectType, jObject, value);

        return value;
    }

    private static void PopulateAutoProperties(Type objectType, JObject jObject, object value)
    {
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var p in properties.Where(IsAutoProperty))
        {
            var token = jObject[p.Name];
            var obj = token != null
                ? token.ToObject(p.PropertyType)
                : p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null;

            p.SetValue(value, obj);
        }
    }
    private static void PopulateFields(Type objectType, JObject jObject, object value)
    {
        var fields =
            objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var f in fields.Where(f => !f.Name.Contains("<")))
        {
            var token = jObject[f.Name];
            var obj = token != null
                ? token.ToObject(f.FieldType)
                : f.FieldType.IsValueType ? Activator.CreateInstance(f.FieldType) : null;

            f.SetValue(value, obj);
        }
    }


    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var objectType=value.GetType();

        writer.WriteStartObject();

        WriteAutoProperties(writer, value, serializer, objectType);
        WriteFields(writer, value, serializer, objectType);

        writer.WriteEndObject();
    }

    private static void WriteFields(JsonWriter writer, object value, JsonSerializer serializer, Type objectType)
    {
        var fields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var f in fields.Where(f => !f.Name.Contains("<")))
        {
            writer.WritePropertyName(f.Name);
            serializer.Serialize(writer, f.GetValue(value));
        }
    }

    private static void WriteAutoProperties(JsonWriter writer, object value, JsonSerializer serializer, Type objectType)
    {
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var p in properties.Where(IsAutoProperty))
        {
            writer.WritePropertyName(p.Name);
            serializer.Serialize(writer, p.GetValue(value));
        }
    }

    public static bool IsAutoProperty(PropertyInfo prop)
    {
        return prop.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                                 .Any(f => f.Name.Contains("<" + prop.Name + ">"));
    }
}
工作原理:

[JsonConverter(typeof (CustomSerializer))]
public struct CustomStruct
{
    public int PublicInt;
    private int _privateInt;
    public string PublicString;
    private string _privateString;

    public int AutoInt { get; set; }
    public string AutoString { get; set; }

    public int ManualInt 
    {
        get{return _privateInt;}
        set { _privateInt = value; }
    }

    public string ManualString
    {
        get { return _privateString; }
        set { _privateString = value; }
    }
}

class Program
{
    private static void Main(string[] args)
    {
        var obj = new CustomStruct()
        {
            AutoInt = 10,
            AutoString = "autostring",
            ManualInt = 5,
            ManualString = "manualstring",
            PublicInt = 20,
            PublicString = "publicstring"
        };

        var json = JsonConvert.SerializeObject(obj,Formatting.Indented);

        var dObj = JsonConvert.DeserializeObject<CustomStruct>(json);
    }
}
public class CustomSerializer : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return typeof (CustomSerializer) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);

        var value = existingValue ?? Activator.CreateInstance(objectType);

        PopulateAutoProperties(objectType, jObject, value);
        PopulateFields(objectType, jObject, value);

        return value;
    }

    private static void PopulateAutoProperties(Type objectType, JObject jObject, object value)
    {
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var p in properties.Where(IsAutoProperty))
        {
            var token = jObject[p.Name];
            var obj = token != null
                ? token.ToObject(p.PropertyType)
                : p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null;

            p.SetValue(value, obj);
        }
    }
    private static void PopulateFields(Type objectType, JObject jObject, object value)
    {
        var fields =
            objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var f in fields.Where(f => !f.Name.Contains("<")))
        {
            var token = jObject[f.Name];
            var obj = token != null
                ? token.ToObject(f.FieldType)
                : f.FieldType.IsValueType ? Activator.CreateInstance(f.FieldType) : null;

            f.SetValue(value, obj);
        }
    }


    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var objectType=value.GetType();

        writer.WriteStartObject();

        WriteAutoProperties(writer, value, serializer, objectType);
        WriteFields(writer, value, serializer, objectType);

        writer.WriteEndObject();
    }

    private static void WriteFields(JsonWriter writer, object value, JsonSerializer serializer, Type objectType)
    {
        var fields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var f in fields.Where(f => !f.Name.Contains("<")))
        {
            writer.WritePropertyName(f.Name);
            serializer.Serialize(writer, f.GetValue(value));
        }
    }

    private static void WriteAutoProperties(JsonWriter writer, object value, JsonSerializer serializer, Type objectType)
    {
        var properties =
            objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var p in properties.Where(IsAutoProperty))
        {
            writer.WritePropertyName(p.Name);
            serializer.Serialize(writer, p.GetValue(value));
        }
    }

    public static bool IsAutoProperty(PropertyInfo prop)
    {
        return prop.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                                 .Any(f => f.Name.Contains("<" + prop.Name + ">"));
    }
}
C#编译器将为每个自动属性创建一个Back字段,其名称为pattern
k#u BackingField
,因此基本上我们可以利用此模式并找到它们。(注意:此代码段可能不适用于Mono或未来的.Net编译器)