skip to Main Content

I have the following code, taken from https://learn.microsoft.com/En-Us/dotnet/standard/serialization/system-text-json/custom-contracts#example-serialize-private-fields. It works fine to serialize the fields of Brains.Brain, but when deserializing, the instance created has (a, b, c, d) = (2, 0, 4, 4) when it should be (2, 3, 4, 7). I’ve tried finding more on how to use a Json constructor, but haven’t been able to find much.

Would someone be able to direct me to if it is on the microsoft documentation (although I haven’t found it); somewhere else where it is documented; or some example code on how I should be using it or something else which solves this problem.

using System.IO;
using System.Linq;
using System.Text.Json;
//
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace BinaryFiles
{
    class Program
    {
        static void Main(string[] args)
        {

            Brains.Brain b = new(3);
            Type btype = typeof(Brains).GetNestedTypes().Where(brain => (brain.GetInterface("IBrain") != null)).ToArray()[0];
            Loader.Save("test", b, btype);
            b.test();

            IBrain newB = Loader.Load("test", btype);
            newB.test();

        }
    }

    internal interface IBrain
    {
        public void test();
    }
    class Brains {
        [JsonIncludePrivateFields]
        public class Brain : IBrain 
        {
            private int a = 2;
            private int b;
            public int c = 4;
            public int d;

            /*
            [JsonConstructor]
            public Brain(int a, int b, int c, int d) =>
            (this.a, this.b, this.c, this.d) = (a, b, c, d);
            */

            public Brain(int B)
            {
                this.b = B;
                this.d = B + 4;
            }
            public void test()
            {
                Console.WriteLine($"{a} {b} {c} {d}");
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class JsonIncludePrivateFieldsAttribute : Attribute { }

    internal static class Loader
    {
        static void AddPrivateFieldsModifier(JsonTypeInfo jsonTypeInfo)
        {
            if (jsonTypeInfo.Kind != JsonTypeInfoKind.Object)
                return;

            if (!jsonTypeInfo.Type.IsDefined(typeof(JsonIncludePrivateFieldsAttribute), inherit: false))
                return;

            foreach (FieldInfo field in jsonTypeInfo.Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
            {
                JsonPropertyInfo jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(field.FieldType, field.Name);
                jsonPropertyInfo.Get = field.GetValue;
                jsonPropertyInfo.Set = field.SetValue;

                jsonTypeInfo.Properties.Add(jsonPropertyInfo);
            }
        }

        public static void Save(string fileName, IBrain brain, Type brainType)
        {
            var options = new JsonSerializerOptions
            {
                IncludeFields = true,
                WriteIndented = true,
                TypeInfoResolver = new DefaultJsonTypeInfoResolver
                {
                    Modifiers = { AddPrivateFieldsModifier }
                }
            };
            Console.WriteLine(JsonSerializer.Serialize(brain, brainType, options));
            File.WriteAllText(fileName + ".json", JsonSerializer.Serialize(brain, options));
        }

        public static IBrain Load(string fileName, Type brainType)
        {
            var options = new JsonSerializerOptions
            {
                IncludeFields = true,
                WriteIndented = true,
                TypeInfoResolver = new DefaultJsonTypeInfoResolver
                {
                    Modifiers = { AddPrivateFieldsModifier }
                }
            };
            return (IBrain)JsonSerializer.Deserialize(File.ReadAllText(fileName + ".json"), brainType, options);
        }
    }
}```

2

Answers


  1. Chosen as BEST ANSWER

    Not sure what I changed, but it works now for some reason? Edit: It was adding brainType to the serializer.

    using System;
    using System.IO;
    using System.Linq;
    //
    using System.Reflection;
    using System.Text.Json;
    using System.Text.Json.Serialization;
    using System.Text.Json.Serialization.Metadata;
    
    namespace BinaryFiles
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                Brains.Brain b = new(3);
                Type btype = typeof(Brains).GetNestedTypes().Where(brain => (brain.GetInterface("IBrain") != null)).ToArray()[0];
                Loader.Save("test", b, btype);
                b.test();
    
                IBrain newB = Loader.Load("test", btype);
                newB.test();
    
            }
        }
    
        internal interface IBrain
        {
            public void test();
        }
    
        class Brains
        {
            [JsonIncludePrivateFields]
            public class Brain : IBrain
            {
                private int a = 2;
                private int b;
                public int c = 4;
                public int d;
    
                public Brain() // for use by deserializer
                {
                    Console.WriteLine("called");
                }
    
                public Brain(int B)
                {
                    this.b = B;
                    this.d = B + 4;
                    this.a = 1;
                }
                public void test()
                {
                    Console.WriteLine($"{a} {b} {c} {d}");
                }
            }
        }
    
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
        public class JsonIncludePrivateFieldsAttribute : Attribute { }
    
        internal static class Loader
        {
            static void AddPrivateFieldsModifier(JsonTypeInfo jsonTypeInfo)
            {
                if (jsonTypeInfo.Kind != JsonTypeInfoKind.Object)
                    return;
    
                if (!jsonTypeInfo.Type.IsDefined(typeof(JsonIncludePrivateFieldsAttribute), inherit: false))
                    return;
    
                foreach (FieldInfo field in jsonTypeInfo.Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    JsonPropertyInfo jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(field.FieldType, field.Name);
                    jsonPropertyInfo.Get = field.GetValue;
                    jsonPropertyInfo.Set = field.SetValue;
    
                    jsonTypeInfo.Properties.Add(jsonPropertyInfo);
                }
            }
    
            public static void Save(string fileName, IBrain brain, Type brainType)
            {
                var options = new JsonSerializerOptions
                {
                    IncludeFields = true,
                    WriteIndented = true,
                    TypeInfoResolver = new DefaultJsonTypeInfoResolver
                    {
                        Modifiers = { AddPrivateFieldsModifier }
                    }
                };
                
                Console.WriteLine(JsonSerializer.Serialize(brain, brainType, options));
                //JsonSerializer.SerializeToDocument();
                File.WriteAllText(fileName + ".json", JsonSerializer.Serialize(brain, brainType, options));
            }
    
            public static IBrain Load(string fileName, Type brainType)
            {
                var options = new JsonSerializerOptions
                {
                    IncludeFields = true,
                    WriteIndented = true,
                    TypeInfoResolver = new DefaultJsonTypeInfoResolver
                    {
                        Modifiers = { AddPrivateFieldsModifier }
                    }
                };
                Console.WriteLine(File.ReadAllText(fileName + ".json"));
                return (IBrain)JsonSerializer.Deserialize(File.ReadAllText(fileName + ".json"), brainType, options);
            }
        }
    }```
    

  2. Not sure what you did wrong but I managed to make it work this (simple) way:

    class Brains
    {
        public class Brain : IBrain
        {
            [JsonInclude]
            private int a = 2;
            [JsonInclude]
            private int b;
            [JsonInclude]
            public int c = 4;
            [JsonInclude]
            public int d;
    
        
            [JsonConstructor]
            public Brain(int a, int b, int c, int d) =>
        (this.a, this.b, this.c, this.d) = (a, b, c, d);               
    
    
            public Brain(int B)
            {
                this.b = B;
                this.d = B + 4;
            }
    
            public void test()
            {
                Console.WriteLine($"{a} {b} {c} {d}");
            }
       }
    }
    

    and then:

    Brains.Brain b = new Brains.Brain(3);           
    b.test();
    var serialized = JsonSerializer.Serialize(b);
    
    var newB = JsonSerializer.Deserialize<Brains.Brain>(serialized);
    newB.test();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search