Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

Reference Newtonsoft.Json.Utilities.AotHelper

Kalle Jillheden edited this page Jan 4, 2020 · 10 revisions

AotHelper Class

Namespace Newtonsoft.Json.Utilities

Description

Utility class to enforce ahead of time (AOT) compilation of types.

This class does not need to be added to a script that's added to a GameObject. It just needs to be compiled. Inheriting from UnityEngine.MonoBehaviour will ensure to always be compiled.

Methods

AotHelper.Ensure

Description

Don't run action but let a compiler detect the code in action as an executable block.

Will not run action but the compiler will still compile the content of the action as if it would run.

Signature

public static void Ensure(Action action)

Remarks

All other Ensure- methods base off of this method.

Example

Ensures the method MyMethod is not stripped.

Note: Was unable to get this to trigger. This example is not valid, but the theory is correct.

using System.Reflection;
using Newtonsoft.Json.Utilities;
using UnityEngine;

public class EnsureExample : MonoBehaviour
{
    private void Awake()
    {
        AotHelper.Ensure(() => {
            new MyOtherClass().MyMethod("");
        });
    }

    private void Start()
    {
        print("Before");
        
        var myOtherClass = new MyOtherClass();
        var myMethod = typeof(MyOtherClass).GetMethod("MyMethod", BindingFlags.NonPublic | BindingFlags.Instance);
        myMethod.Invoke(myOtherClass, new [] {"Hey: "});

        print("After");
    }

    public class MyOtherClass
    {
        private void MyMethod(string prefix) {
            print(prefix + "Foo.");
        }
    }
}

Console output:

Before
Hey: Foo.
After

AotHelper.EnsureType

Description

Ensures that the default constructor is compiled for a given type.

Signature

public static void EnsureType<T>()
    where T : new()

Example

Ensures that MyData<string> can be constructed, because new MyData<string>() is never called explicitly.

Usage of EnsureType here fixes error:

JsonSerializationException: Unable to find a constructor to use for type EnsureTypeExample+MyData`1[System.String]. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'valueA', line 2, position 13.
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Utilities;
using UnityEngine;
 
public class EnsureTypeExample : MonoBehaviour
{
    private void Awake()
    {
        AotHelper.EnsureType<MyData<string>>();
    }

    private void Start()
    {
        var json = @"{
    ""valueA"": ""foo"",
    ""valueB"": ""bar"",
}";
        var data = JsonConvert.DeserializeObject<MyData<string>>(json);
        print(data.valueA);
        print(data.valueB);
    }

    private class MyData<T>
    {
        public T valueA;
        public T valueB;
    }
}

Console output:

foo
bar

AotHelper.EnsureList

Description

Ensure generic list type can be (de)serialized on AOT environment.

Signature

public static void EnsureList<T>()

Remarks

Ensures the following constructors:

System.Collections.Generic.List<T>()
System.Collections.Generic.HashSet<T>()
Newtonsoft.Json.Utilities.CollectionWrapper<T>(IList list)
Newtonsoft.Json.Utilities.CollectionWrapper<T>(ICollection<T> list)

Example

Ensures the type decimal can be used in lists in act of deserializing json.

Usage of EnsureList here fixes error:

ExecutionEngineException: Attempting to call method 'Newtonsoft.Json.Utilities.CollectionWrapper`1[[System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Utilities;
using UnityEngine;
 
public class EnsureListExample : MonoBehaviour
{
    private void Awake()
    {
        AotHelper.EnsureList<decimal>();
    }

    private void Start()
    {
        var json = @"{
    ""myList"": [
        125251314,
        35135.135,
        12345.678
    ]
}";
        var data = JsonConvert.DeserializeObject<MyData>(json);
        print(data.myList[0]);
        print(data.myList[1]);
        print(data.myList[2]);
    }

    private class MyData
    {
        public IList<decimal> myList;
    }
}

Console output:

125251314
35135.135
12345.678

AotHelper.EnsureDictionary

Description

Ensure generic dictionary type can be (de)serialized on AOT environment.

Signature

public static void EnsureDictionary<TKey, TValue>()

Remarks

Ensures the following constructors:

System.Collections.Generic.Dictionary<TKey, TValue>()
Newtonsoft.Json.Utilities.DictionaryWrapper<TKey, TValue>(IDictionary dictionary)
Newtonsoft.Json.Utilities.DictionaryWrapper<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
Newtonsoft.Json.Serialization.DefaultContractResolver.EnumerableDictionaryWrapper<TKey, TValue>(IEnumerable<KeyValuePair<TEnumeratorKey, TEnumeratorValue>> e)

Example

Ensures the type dictionary of type <string, ulong> can be used in lists in act of deserializing json.

Usage of EnsureDictionary here fixes error:

JsonSerializationException: Unable to find a constructor to use for type EnsureDictionaryExample+MyData. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'myDictionary', line 2, position 19.
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Utilities;
using UnityEngine;
 
public class EnsureDictionaryExample : MonoBehaviour
{
    private void Awake()
    {
        AotHelper.EnsureDictionary<string, ulong>();
    }

    private void Start()
    {
        var json = @"{
    ""myDictionary"": {
        ""tripp"": 351353153,
        ""trapp"": 123453151343678,
        ""trull"": 315136125234151314
    }
}";
        var data = JsonConvert.DeserializeObject<MyData>(json);
        print("tripp: " + data.myDictionary["tripp"]);
        print("trapp: " + data.myDictionary["trapp"]);
        print("trull: " + data.myDictionary["trull"]);
    }

    private class MyData
    {
        public IDictionary<string, ulong> myDictionary;
    }
}

Console output:

tripp: 351353153
trapp: 123453151343678
trull: 315136125234151314