diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index b9b645be..cd17d3a0 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -538,7 +538,7 @@ namespace Newtonsoft.Json Guid g; if (s.Length == 0) { - data = new byte[0]; + data = CollectionUtils.ArrayEmpty(); } else if (ConvertUtils.TryConvertGuid(s, out g)) { diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 7db4820a..56e0ee72 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -146,7 +146,7 @@ namespace Newtonsoft.Json byte[] data; if (_stringReference.Length == 0) { - data = new byte[0]; + data = CollectionUtils.ArrayEmpty(); } else if (_stringReference.Length == 36 && ConvertUtils.TryConvertGuid(_stringReference.ToString(), out g)) { diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs index ed666842..a7536070 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs @@ -88,7 +88,7 @@ namespace Newtonsoft.Json.Linq.JsonPath return JPath.Evaluate(pathFilters, root, t, false); } - return new JToken[0]; + return CollectionUtils.ArrayEmpty(); } public override bool IsMatch(JToken root, JToken t) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 85bd000a..acaab3c2 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -2274,7 +2274,7 @@ namespace Newtonsoft.Json.Serialization return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.OverrideCreator, id); } - newObject = objectContract.OverrideCreator(new object[0]); + newObject = objectContract.OverrideCreator(CollectionUtils.ArrayEmpty()); } else if (objectContract.DefaultCreator != null && (!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParameterizedCreator == null)) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index 055c55a7..6ca5e43a 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -745,7 +745,7 @@ namespace Newtonsoft.Json.Serialization bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, containerProperty); - SerializeMultidimensionalArray(writer, values, contract, member, writer.Top, new int[0]); + SerializeMultidimensionalArray(writer, values, contract, member, writer.Top, CollectionUtils.ArrayEmpty()); if (hasWrittenMetadataObject) { diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs index 06b86df0..6bfef174 100644 --- a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -29,12 +29,16 @@ using System.Collections.ObjectModel; using System.Reflection; using System.Text; using System.Collections; +using System.Diagnostics; #if NET20 using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; #endif using System.Globalization; +#if !(NET20 || NET35 || NET40 || PORTABLE40) +using System.Runtime.CompilerServices; +#endif using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Utilities @@ -340,9 +344,30 @@ namespace Newtonsoft.Json.Utilities } Array multidimensionalArray = Array.CreateInstance(type, dimensions.ToArray()); - CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, new int[0]); + CopyFromJaggedToMultidimensionalArray(values, multidimensionalArray, ArrayEmpty()); return multidimensionalArray; } + + // 4.6 has Array.Empty to return a cached empty array. Lacking that in other + // frameworks, Enumerable.Empty happens to be implemented as a cached empty + // array in all versions (in .NET Core the same instance as Array.Empty). + // 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 even when not available. +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static T[] ArrayEmpty() + { + T[] array = Enumerable.Empty() as T[]; + Debug.Assert(array != null); + // Defensively guard against a version of Linq where Enumerable.Empty doesn't + // return an array, but throw in debug versions so a better strategy can be + // used if that ever happens. + return array ?? new T[0]; + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs index 7fb0100d..56edbcb7 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs @@ -37,7 +37,7 @@ namespace Newtonsoft.Json.Utilities { public virtual IEnumerable GetDynamicMemberNames(T instance) { - return new string[0]; + return CollectionUtils.ArrayEmpty(); } public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object result) diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs index 3569d176..46dc1705 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs @@ -166,7 +166,7 @@ namespace Newtonsoft.Json.Utilities private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion); - private static readonly Expression[] NoArgs = new Expression[0]; + private static Expression[] NoArgs => CollectionUtils.ArrayEmpty(); private static IEnumerable GetArgs(params DynamicMetaObject[] args) { diff --git a/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs b/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs index a83d311b..e61f9178 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs @@ -158,7 +158,7 @@ namespace Newtonsoft.Json.Utilities public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { - DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { }); + DynamicMetaObject retMetaObject = _innerBinder.Bind(target, CollectionUtils.ArrayEmpty()); NoThrowExpressionVisitor noThrowVisitor = new NoThrowExpressionVisitor(); Expression resultExpression = noThrowVisitor.Visit(retMetaObject.Expression); diff --git a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs index 32581bcf..de2fa1b9 100644 --- a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs @@ -87,40 +87,45 @@ namespace Newtonsoft.Json.Utilities { ParameterInfo[] parametersInfo = method.GetParameters(); - Expression[] argsExpression = new Expression[parametersInfo.Length]; - IList refParameterMap = new List(); - - for (int i = 0; i < parametersInfo.Length; i++) + Expression[] argsExpression; + IList refParameterMap; + if (parametersInfo.Length == 0) { - ParameterInfo parameter = parametersInfo[i]; - Type parameterType = parameter.ParameterType; - bool isByRef = false; - if (parameterType.IsByRef) + argsExpression = CollectionUtils.ArrayEmpty(); + refParameterMap = CollectionUtils.ArrayEmpty(); + } + else + { + argsExpression = new Expression[parametersInfo.Length]; + refParameterMap = new List(); + + for (int i = 0; i < parametersInfo.Length; i++) { - parameterType = parameterType.GetElementType(); - isByRef = true; - } - - Expression indexExpression = Expression.Constant(i); - - Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression); - - Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef); - - if (isByRef) - { - ParameterExpression variable = Expression.Variable(parameterType); - refParameterMap.Add(new ByRefParameter + ParameterInfo parameter = parametersInfo[i]; + Type parameterType = parameter.ParameterType; + bool isByRef = false; + if (parameterType.IsByRef) { - Value = argExpression, - Variable = variable, - IsOut = parameter.IsOut - }); + parameterType = parameterType.GetElementType(); + isByRef = true; + } - argExpression = variable; + Expression indexExpression = Expression.Constant(i); + + Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression); + + Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef); + + if (isByRef) + { + ParameterExpression variable = Expression.Variable(parameterType); + refParameterMap.Add(new ByRefParameter {Value = argExpression, Variable = variable, IsOut = parameter.IsOut}); + + argExpression = variable; + } + + argsExpression[i] = argExpression; } - - argsExpression[i] = argExpression; } Expression callExpression; diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 6d8e21ef..94f3ebbf 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -90,7 +90,7 @@ namespace Newtonsoft.Json.Utilities #if !(PORTABLE40 || PORTABLE) EmptyTypes = Type.EmptyTypes; #else - EmptyTypes = new Type[0]; + EmptyTypes = CollectionUtils.ArrayEmpty(); #endif }