kevin-montrose / Jil

Fast .NET JSON (De)Serializer, Built On Sigil
MIT License
2.15k stars 253 forks source link

Serializing a Func member with PrettyPrint throws InvalidOperationException #325

Closed MaxHorstmann closed 5 years ago

MaxHorstmann commented 5 years ago

Serializing a Func member works fine without Options.ISO8601PrettyPrintIncludeInherited, but throws an InvalidOperationException with Options.ISO8601PrettyPrintIncludeInherited:

using System;
using Newtonsoft.Json;
using Jil;

namespace MyConsoleApp
{
    class Foo
    {
        public Func<string, string> Bar { get; }
        public Foo(Func<string, string> bar) { Bar = bar; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var foo = new Foo(x => x);
            Console.WriteLine(JsonConvert.SerializeObject(foo, Formatting.Indented));  // ok
            Console.WriteLine(JSON.Serialize(foo));  // ok
            Console.WriteLine(JSON.Serialize(foo, Options.ISO8601PrettyPrintIncludeInherited));  
            // ^^^ System.InvalidOperationException: 'Method may only be called on a Type for which Type.IsGenericParameter is true.'
        }
    }
}
MaxHorstmann commented 5 years ago

Btw, Newtonsoft serializes the Func property like this:

{
  "Bar": {
    "Method": {
      "Name": "<Main>b__0_0",
      "AssemblyName": "ConsoleApp8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "ClassName": "MyConsoleApp.Program+<>c",
      "Signature": "System.String <Main>b__0_0(System.String)",
      "Signature2": "System.String <Main>b__0_0(System.String)",
      "MemberType": 8,
      "GenericArguments": null
    },
    "Target": {}
  }
}

JIL (when it doesn't throw) just produces this:

{"Bar":{}}
kevin-montrose commented 5 years ago

This is by design, as a consequence of setting the IncludeInherited results in Jil trying to serialize the Delegate-provided members of bar, which ultimately includes a Type whose GenericParameterPosition property throws and exception upon access.

Basically, Jil doesn't special case Type or Delegate - and Type's parameters are not safe to access arbitrarily. I'd suggest using a different Options, or adding [IgnoreDataMember] to your delegate members.