Why does Json.NET serialization fail with [Seriali

2020-03-25 17:43发布

问题:

According to these release notes, Json.NET now supports the SerializableAttribute:

Json.NET now detects types that have the SerializableAttribute and serializes all the fields on that type, both public and private, and ignores the properties.

I have the following sample code that throws a JsonSerializationException:

Error getting value from 'CS$<>9__CachedAnonymousMethodDelegate1' on 'ConsoleApplication1.MyType'.

If I comment the TotalWithLambda property, then the serialization succeeds as expected. In fact, I get the following results:

  • Leave [Serializable], leave TotalWithLambda: throws JsonSerializationException
  • Leave [Serializable], remove TotalWithLambda: serializes "myList" only
  • Remove [Serializable], leave TotalWithLambda: serializes "myList", "Total", and "TotalWithLambda"
  • Remove [Serializable], remove TotalWithLambda: serializes "myList" and "Total"

I understand all of these cases except the first one. Why does the combination of [Serializable] and a read-only property with a lambda in it cause this exception?

namespace ConsoleApplication1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;

    class Program
    {
        static void Main(string[] args)
        {
            var foo = new MyType();
            foo.myList = new List<int>() { 0, 1, 2, 3 };

            var returnVal = JsonConvert.SerializeObject(foo);

            Console.WriteLine("Return: " + returnVal.ToString());
            Console.ReadKey();
        }
    }

    [Serializable]
    class MyType
    {
        public IList<int> myList;
        public int Total { get { return this.myList.Sum(); } }
        public int TotalWithLambda { get { return this.myList.Sum(x => x); } }
    }

}

回答1:

I installed and used JustDecompile and found that the compiler adds a field and a method to the class when the lambda is uncommented:

public class MyType
{
    [CompilerGenerated]
    private static Func<int, int> CS$<>9__CachedAnonymousMethodDelegate1;

    [CompilerGenerated]
    private static int <get_TotalWithLambda>b__0(int x) { ... }

    // ... plus the other class members ...
}

When the class has SerializableAttribute on it, Json.NET tries to serialize the private field, but can't since it's of type Func<int, int>. Removing the SerializableAttribute instructs Json.NET to ignore private fields and so it doesn't cause a problem.

Update: Json.NET 4.5 release 3 now makes this only a problem if you explicitly set IgnoreSerializableAttribute=false, or it can be resolved by adding the JsonObjectAttribute to the class..



回答2:

I've changed IgnoreSerializableAttribute to true by default in release 3 which undoes the breaking change introduced in release 2 - http://json.codeplex.com/releases/view/85975

You can read more about it here - http://json.codeplex.com/discussions/351981