Fix allocating empty arrays and more nullable warnings

This commit is contained in:
James Newton-King
2019-08-19 17:38:08 +12:00
parent 6471010c56
commit d75074f30c
16 changed files with 109 additions and 97 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
<FSharpCorePackageVersion>4.2.3</FSharpCorePackageVersion>
<MicrosoftCodeAnalysisFxCopAnalyzersPackageVersion>2.9.2</MicrosoftCodeAnalysisFxCopAnalyzersPackageVersion>
<MicrosoftCSharpPackageVersion>4.3.0</MicrosoftCSharpPackageVersion>
<MicrosoftSourceLinkGitHubPackageVersion>1.0.0-beta2-18618-05</MicrosoftSourceLinkGitHubPackageVersion>
<MicrosoftSourceLinkGitHubPackageVersion>1.0.0-beta2-19367-01</MicrosoftSourceLinkGitHubPackageVersion>
<MicrosoftNetCompilersToolsetPackageVersion>3.3.0-beta1-final</MicrosoftNetCompilersToolsetPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.7.2</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.8.1</MoqPackageVersion>
@@ -28,6 +28,7 @@ using System;
using System.Globalization;
using Newtonsoft.Json.Utilities;
using System.Collections.Generic;
using System.Diagnostics;
#if HAVE_ADO_NET
using System.Data.SqlTypes;
#endif
@@ -42,7 +43,7 @@ namespace Newtonsoft.Json.Converters
#if HAVE_LINQ
private const string BinaryTypeName = "System.Data.Linq.Binary";
private const string BinaryToArrayName = "ToArray";
private static ReflectionObject _reflectionObject;
private static ReflectionObject? _reflectionObject;
#endif
/// <summary>
@@ -70,6 +71,8 @@ namespace Newtonsoft.Json.Converters
if (value.GetType().FullName == BinaryTypeName)
{
EnsureReflectionObject(value.GetType());
Debug.Assert(_reflectionObject != null);
return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName)!;
}
#endif
@@ -139,6 +142,7 @@ namespace Newtonsoft.Json.Converters
if (t.FullName == BinaryTypeName)
{
EnsureReflectionObject(t);
Debug.Assert(_reflectionObject != null);
return _reflectionObject.Creator!(data);
}
@@ -89,28 +89,28 @@ namespace Newtonsoft.Json.Converters
// need to get declaring type to avoid duplicate Unions in cache
// hacky but I can't find an API to get the declaring type without GetUnionCases
object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null)!;
object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!;
object caseInfo = cases.First();
Type unionType = (Type)FSharpUtils.GetUnionCaseInfoDeclaringType(caseInfo)!;
Type unionType = (Type)FSharpUtils.Instance.GetUnionCaseInfoDeclaringType(caseInfo)!;
return unionType;
}
private static Union CreateUnion(Type t)
{
Union u = new Union((FSharpFunction)FSharpUtils.PreComputeUnionTagReader(null, t, null), new List<UnionCase>());
Union u = new Union((FSharpFunction)FSharpUtils.Instance.PreComputeUnionTagReader(null, t, null), new List<UnionCase>());
object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null)!;
object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!;
foreach (object unionCaseInfo in cases)
{
UnionCase unionCase = new UnionCase(
(int)FSharpUtils.GetUnionCaseInfoTag(unionCaseInfo),
(string)FSharpUtils.GetUnionCaseInfoName(unionCaseInfo),
(PropertyInfo[])FSharpUtils.GetUnionCaseInfoFields(unionCaseInfo)!,
(FSharpFunction)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null),
(FSharpFunction)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null));
(int)FSharpUtils.Instance.GetUnionCaseInfoTag(unionCaseInfo),
(string)FSharpUtils.Instance.GetUnionCaseInfoName(unionCaseInfo),
(PropertyInfo[])FSharpUtils.Instance.GetUnionCaseInfoFields(unionCaseInfo)!,
(FSharpFunction)FSharpUtils.Instance.PreComputeUnionReader(null, unionCaseInfo, null),
(FSharpFunction)FSharpUtils.Instance.PreComputeUnionConstructor(null, unionCaseInfo, null));
u.Cases.Add(unionCase);
}
@@ -290,7 +290,7 @@ namespace Newtonsoft.Json.Converters
return false;
}
return (bool)FSharpUtils.IsUnion(null, objectType, null);
return (bool)FSharpUtils.Instance.IsUnion(null, objectType, null);
}
}
}
@@ -28,6 +28,7 @@ using System;
using Newtonsoft.Json.Serialization;
using System.Globalization;
using Newtonsoft.Json.Utilities;
using System.Diagnostics;
namespace Newtonsoft.Json.Converters
{
@@ -42,7 +43,7 @@ namespace Newtonsoft.Json.Converters
private const string TypePropertyName = "Type";
private const string ValuePropertyName = "Value";
private static ReflectionObject _reflectionObject;
private static ReflectionObject? _reflectionObject;
/// <summary>
/// Writes the JSON representation of the object.
@@ -59,6 +60,7 @@ namespace Newtonsoft.Json.Converters
}
EnsureReflectionObject(value.GetType());
Debug.Assert(_reflectionObject != null);
DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
@@ -115,6 +117,7 @@ namespace Newtonsoft.Json.Converters
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
EnsureReflectionObject(objectType);
Debug.Assert(_reflectionObject != null);
object entityKeyMember = _reflectionObject.Creator!();
+1 -1
View File
@@ -59,7 +59,7 @@ namespace Newtonsoft.Json
/// To serialize without using any default settings create a <see cref="JsonSerializer"/> with
/// <see cref="JsonSerializer.Create()"/>.
/// </summary>
public static Func<JsonSerializerSettings> DefaultSettings { get; set; }
public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }
/// <summary>
/// Represents JavaScript's boolean value <c>true</c> as a string. This field is read-only.
+1 -1
View File
@@ -81,7 +81,7 @@ namespace Newtonsoft.Json
/// <summary>
/// Occurs when the <see cref="JsonSerializer"/> errors during serialization and deserialization.
/// </summary>
public virtual event EventHandler<ErrorEventArgs> Error;
public virtual event EventHandler<ErrorEventArgs>? Error;
/// <summary>
/// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
+2 -2
View File
@@ -72,13 +72,13 @@ namespace Newtonsoft.Json.Linq
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler? PropertyChanged;
#if HAVE_INOTIFY_PROPERTY_CHANGING
/// <summary>
/// Occurs when a property value is changing.
/// </summary>
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangingEventHandler? PropertyChanging;
#endif
/// <summary>
+1 -1
View File
@@ -59,7 +59,7 @@ namespace Newtonsoft.Json.Linq
, IDynamicMetaObjectProvider
#endif
{
private static JTokenEqualityComparer _equalityComparer;
private static JTokenEqualityComparer? _equalityComparer;
private JContainer? _parent;
private JToken? _previous;
@@ -37,7 +37,7 @@ namespace Newtonsoft.Json.Serialization
{
private static readonly object TypeContractCacheLock = new object();
private static readonly DefaultJsonNameTable NameTable = new DefaultJsonNameTable();
private static Dictionary<StructMultiKey<Type, Type>, JsonContract> _contractCache;
private static Dictionary<StructMultiKey<Type, Type>, JsonContract>? _contractCache;
/// <summary>
/// Initializes a new instance of the <see cref="CamelCasePropertyNamesContractResolver"/> class.
@@ -65,7 +65,7 @@ namespace Newtonsoft.Json.Serialization
// for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances
StructMultiKey<Type, Type> key = new StructMultiKey<Type, Type>(GetType(), type);
Dictionary<StructMultiKey<Type, Type>, JsonContract> cache = _contractCache;
Dictionary<StructMultiKey<Type, Type>, JsonContract>? cache = _contractCache;
if (cache == null || !cache.TryGetValue(key, out JsonContract contract))
{
contract = CreateContract(type);
@@ -318,7 +318,7 @@ namespace Newtonsoft.Json.Serialization
if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName)
{
FSharpUtils.EnsureInitialized(underlyingType.Assembly());
_parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType!);
_parameterizedCreator = FSharpUtils.Instance.CreateSeq(CollectionItemType!);
}
}
#endif
@@ -179,7 +179,7 @@ namespace Newtonsoft.Json.Serialization
if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName)
{
FSharpUtils.EnsureInitialized(underlyingType.Assembly());
_parameterizedCreator = FSharpUtils.CreateMap(keyType, valueType);
_parameterizedCreator = FSharpUtils.Instance.CreateMap(keyType, valueType);
}
#endif
}
@@ -38,7 +38,7 @@ namespace Newtonsoft.Json.Serialization
private readonly JsonSerializerInternalWriter? _serializerWriter;
private readonly JsonSerializer _serializer;
public override event EventHandler<ErrorEventArgs> Error
public override event EventHandler<ErrorEventArgs>? Error
{
add => _serializer.Error += value;
remove => _serializer.Error -= value;
@@ -63,7 +63,7 @@ namespace Newtonsoft.Json.Serialization
#if !(NET20 || DOTNET)
private static readonly ThreadSafeStore<Type, Type?> AssociatedMetadataTypesCache = new ThreadSafeStore<Type, Type?>(GetAssociateMetadataTypeFromAttribute);
private static ReflectionObject _metadataTypeAttributeReflectionObject;
private static ReflectionObject? _metadataTypeAttributeReflectionObject;
#endif
public static T? GetCachedAttribute<T>(object attributeProvider) where T : Attribute
@@ -366,26 +366,16 @@ namespace Newtonsoft.Json.Utilities
return multidimensionalArray;
}
// 4.6 has Array.Empty<T> to return a cached empty array. Lacking that in other
// frameworks, Enumerable.Empty<T> happens to be implemented as a cached empty
// array in all versions (in .NET Core the same instance as Array.Empty<T>).
// This includes the internal Linq bridge for 2.0.
// Since this method is simple and only 11 bytes long in a release build it's
// pretty much guaranteed to be inlined, giving us fast access of that cached
// array. With 4.5 and up we use AggressiveInlining just to be sure, so it's
// effectively the same as calling Array.Empty<T> even when not available.
#if HAVE_METHOD_IMPL_ATTRIBUTE
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static T[] ArrayEmpty<T>()
{
T[]? array = Enumerable.Empty<T>() as T[];
Debug.Assert(array != null);
// Defensively guard against a version of Linq where Enumerable.Empty<T> doesn't
// return an array, but throw in debug versions so a better strategy can be
// used if that ever happens.
// Enumerable.Empty<T> no longer returns an empty array in .NET Core 3.0
return EmptyArrayContainer<T>.Empty;
}
private static class EmptyArrayContainer<T>
{
#pragma warning disable CA1825 // Avoid zero-length array allocations.
return array ?? new T[0];
public static readonly T[] Empty = new T[0];
#pragma warning restore CA1825 // Avoid zero-length array allocations.
}
}
@@ -38,6 +38,7 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Globalization;
using Newtonsoft.Json.Serialization;
using System.Diagnostics;
namespace Newtonsoft.Json.Utilities
{
@@ -53,10 +54,10 @@ namespace Newtonsoft.Json.Utilities
private const string CSharpArgumentInfoFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, " + CSharpAssemblyName;
private const string CSharpBinderFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, " + CSharpAssemblyName;
private static object _getCSharpArgumentInfoArray;
private static object _setCSharpArgumentInfoArray;
private static MethodCall<object?, object?> _getMemberCall;
private static MethodCall<object?, object?> _setMemberCall;
private static object? _getCSharpArgumentInfoArray;
private static object? _setCSharpArgumentInfoArray;
private static MethodCall<object?, object?>? _getMemberCall;
private static MethodCall<object?, object?>? _setMemberCall;
private static bool _init;
private static void Init()
@@ -116,6 +117,8 @@ namespace Newtonsoft.Json.Utilities
{
#if !HAVE_REFLECTION_BINDER
Init();
Debug.Assert(_getMemberCall != null);
Debug.Assert(_getCSharpArgumentInfoArray != null);
return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray)!;
#else
return Binder.GetMember(
@@ -127,6 +130,8 @@ namespace Newtonsoft.Json.Utilities
{
#if !HAVE_REFLECTION_BINDER
Init();
Debug.Assert(_setMemberCall != null);
Debug.Assert(_setCSharpArgumentInfoArray != null);
return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray)!;
#else
return Binder.SetMember(
+62 -52
View File
@@ -31,6 +31,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json.Serialization;
using System.Diagnostics;
namespace Newtonsoft.Json.Utilities
{
@@ -53,24 +54,64 @@ namespace Newtonsoft.Json.Utilities
}
}
internal static class FSharpUtils
internal class FSharpUtils
{
private FSharpUtils(Assembly fsharpCoreAssembly)
{
FSharpCoreAssembly = fsharpCoreAssembly;
Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType");
MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static);
IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object?>(isUnionMethodInfo)!;
MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static);
GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object?>(getUnionCasesMethodInfo)!;
Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue");
PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader");
PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader");
PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor");
Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo");
GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Name")!)!;
GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Tag")!)!;
GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("DeclaringType")!)!;
GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(unionCaseInfo.GetMethod("GetFields"));
Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
_ofSeq = listModule.GetMethod("OfSeq");
_mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
}
private static readonly object Lock = new object();
private static FSharpUtils? _instance;
private static bool _initialized;
private static MethodInfo _ofSeq;
private static Type _mapType;
public static FSharpUtils Instance
{
get
{
Debug.Assert(_instance != null);
return _instance;
}
}
public static Assembly FSharpCoreAssembly { get; private set; }
public static MethodCall<object?, object> IsUnion { get; private set; }
public static MethodCall<object?, object> GetUnionCases { get; private set; }
public static MethodCall<object?, object> PreComputeUnionTagReader { get; private set; }
public static MethodCall<object?, object> PreComputeUnionReader { get; private set; }
public static MethodCall<object?, object> PreComputeUnionConstructor { get; private set; }
public static Func<object, object> GetUnionCaseInfoDeclaringType { get; private set; }
public static Func<object, object> GetUnionCaseInfoName { get; private set; }
public static Func<object, object> GetUnionCaseInfoTag { get; private set; }
public static MethodCall<object, object?> GetUnionCaseInfoFields { get; private set; }
private MethodInfo _ofSeq;
private Type _mapType;
public Assembly FSharpCoreAssembly { get; private set; }
public MethodCall<object?, object> IsUnion { get; private set; }
public MethodCall<object?, object> GetUnionCases { get; private set; }
public MethodCall<object?, object> PreComputeUnionTagReader { get; private set; }
public MethodCall<object?, object> PreComputeUnionReader { get; private set; }
public MethodCall<object?, object> PreComputeUnionConstructor { get; private set; }
public Func<object, object> GetUnionCaseInfoDeclaringType { get; private set; }
public Func<object, object> GetUnionCaseInfoName { get; private set; }
public Func<object, object> GetUnionCaseInfoTag { get; private set; }
public MethodCall<object, object?> GetUnionCaseInfoFields { get; private set; }
public const string FSharpSetTypeName = "FSharpSet`1";
public const string FSharpListTypeName = "FSharpList`1";
@@ -78,44 +119,13 @@ namespace Newtonsoft.Json.Utilities
public static void EnsureInitialized(Assembly fsharpCoreAssembly)
{
if (!_initialized)
if (_instance == null)
{
lock (Lock)
{
if (!_initialized)
if (_instance == null)
{
FSharpCoreAssembly = fsharpCoreAssembly;
Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType");
MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static);
IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object?>(isUnionMethodInfo)!;
MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static);
GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object?>(getUnionCasesMethodInfo)!;
Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue");
PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader");
PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader");
PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor");
Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo");
GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Name")!)!;
GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Tag")!)!;
GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("DeclaringType")!)!;
GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(unionCaseInfo.GetMethod("GetFields"));
Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
_ofSeq = listModule.GetMethod("OfSeq");
_mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
#if HAVE_MEMORY_BARRIER
Thread.MemoryBarrier();
#endif
_initialized = true;
_instance = new FSharpUtils(fsharpCoreAssembly);
}
}
}
@@ -156,23 +166,23 @@ namespace Newtonsoft.Json.Utilities
return createFunction;
}
public static ObjectConstructor<object> CreateSeq(Type t)
public ObjectConstructor<object> CreateSeq(Type t)
{
MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType);
}
public static ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
public ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
{
MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator");
MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType);
return (ObjectConstructor<object>)creatorGeneric.Invoke(null, null);
return (ObjectConstructor<object>)creatorGeneric.Invoke(this, null);
}
public static ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
public ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
{
Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue));
ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });