Merge branch 'corefx-converter-args' of https://github.com/pieceofsummer/Newtonsoft.Json into pieceofsummer-corefx-converter-args

This commit is contained in:
James Newton-King
2016-09-13 16:15:20 +12:00
8 changed files with 720 additions and 62 deletions
@@ -1330,6 +1330,310 @@ namespace Newtonsoft.Json.Tests
public string One { get; set; }
}
public class OverloadsJsonConverterer : JsonConverter
{
private readonly string _type;
// constructor with Type argument
public OverloadsJsonConverterer(Type typeParam)
{
_type = "Type";
}
public OverloadsJsonConverterer(object objectParam)
{
_type = string.Format("object({0})", objectParam.GetType().FullName);
}
// primitive type conversions
public OverloadsJsonConverterer(byte byteParam)
{
_type = "byte";
}
public OverloadsJsonConverterer(short shortParam)
{
_type = "short";
}
public OverloadsJsonConverterer(int intParam)
{
_type = "int";
}
public OverloadsJsonConverterer(long longParam)
{
_type = "long";
}
public OverloadsJsonConverterer(double doubleParam)
{
_type = "double";
}
// params argument
public OverloadsJsonConverterer(params int[] intParams)
{
_type = "int[]";
}
public OverloadsJsonConverterer(bool[] intParams)
{
_type = "bool[]";
}
// closest type resolution
public OverloadsJsonConverterer(IEnumerable<string> iEnumerableParam)
{
_type = "IEnumerable<string>";
}
public OverloadsJsonConverterer(IList<string> iListParam)
{
_type = "IList<string>";
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(_type);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(int);
}
}
public class OverloadWithTypeParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), typeof(int))]
public int Overload { get; set; }
}
[Test]
public void JsonConverterConstructor_OverloadWithTypeParam()
{
OverloadWithTypeParameter value = new OverloadWithTypeParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"Type\"}", json);
}
public class OverloadWithUnhandledParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), "str")]
public int Overload { get; set; }
}
[Test]
public void JsonConverterConstructor_OverloadWithUnhandledParam_FallbackToObject()
{
OverloadWithUnhandledParameter value = new OverloadWithUnhandledParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"object(System.String)\"}", json);
}
public class OverloadWithIntParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1)]
public int Overload { get; set; }
}
public class OverloadWithUIntParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1U)]
public int Overload { get; set; }
}
public class OverloadWithLongParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1L)]
public int Overload { get; set; }
}
public class OverloadWithULongParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1UL)]
public int Overload { get; set; }
}
public class OverloadWithShortParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), (short)1)]
public int Overload { get; set; }
}
public class OverloadWithUShortParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), (ushort)1)]
public int Overload { get; set; }
}
public class OverloadWithSByteParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), (sbyte)1)]
public int Overload { get; set; }
}
public class OverloadWithByteParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), (byte)1)]
public int Overload { get; set; }
}
public class OverloadWithCharParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 'a')]
public int Overload { get; set; }
}
public class OverloadWithBoolParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), true)]
public int Overload { get; set; }
}
public class OverloadWithFloatParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1.5f)]
public int Overload { get; set; }
}
public class OverloadWithDoubleParameter
{
[JsonConverter(typeof(OverloadsJsonConverterer), 1.5)]
public int Overload { get; set; }
}
[Test]
public void JsonConverterConstructor_OverloadsWithPrimitiveParams()
{
{
OverloadWithIntParameter value = new OverloadWithIntParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"int\"}", json);
}
{
// uint -> long
OverloadWithUIntParameter value = new OverloadWithUIntParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"long\"}", json);
}
{
OverloadWithLongParameter value = new OverloadWithLongParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"long\"}", json);
}
{
// ulong -> double
OverloadWithULongParameter value = new OverloadWithULongParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"double\"}", json);
}
{
OverloadWithShortParameter value = new OverloadWithShortParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"short\"}", json);
}
{
// ushort -> int
OverloadWithUShortParameter value = new OverloadWithUShortParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"int\"}", json);
}
{
// sbyte -> short
OverloadWithSByteParameter value = new OverloadWithSByteParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"short\"}", json);
}
{
OverloadWithByteParameter value = new OverloadWithByteParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"byte\"}", json);
}
{
// char -> int
OverloadWithCharParameter value = new OverloadWithCharParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"int\"}", json);
}
{
// bool -> (object)bool
OverloadWithBoolParameter value = new OverloadWithBoolParameter();
var json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"object(System.Boolean)\"}", json);
}
{
// float -> double
OverloadWithFloatParameter value = new OverloadWithFloatParameter();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"double\"}", json);
}
{
OverloadWithDoubleParameter value = new OverloadWithDoubleParameter();
var json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"double\"}", json);
}
}
public class OverloadWithArrayParameters
{
[JsonConverter(typeof(OverloadsJsonConverterer), new int[] { 1, 2, 3 })]
public int WithParams { get; set; }
[JsonConverter(typeof(OverloadsJsonConverterer), new bool[] { true, false })]
public int WithoutParams { get; set; }
}
[Test]
public void JsonConverterConstructor_OverloadsWithArrayParams()
{
OverloadWithArrayParameters value = new OverloadWithArrayParameters();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"WithParams\":\"int[]\",\"WithoutParams\":\"bool[]\"}", json);
}
public class OverloadWithBaseType
{
[JsonConverter(typeof(OverloadsJsonConverterer), new object[] { new string[] { "a", "b", "c" } })]
public int Overload { get; set; }
}
[Test]
public void JsonConverterConstructor_OverloadsWithBaseTypes()
{
OverloadWithBaseType value = new OverloadWithBaseType();
string json = JsonConvert.SerializeObject(value);
Assert.AreEqual("{\"Overload\":\"IList<string>\"}", json);
}
[Test]
public void CustomDoubleRounding()
{
@@ -234,6 +234,7 @@
<Compile Include="Utilities\LateBoundReflectionDelegateFactory.cs" />
<Compile Include="Utilities\LinqBridge.cs" />
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MethodBinder.cs" />
<Compile Include="Utilities\MethodCall.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
<Compile Include="Utilities\PropertyNameTable.cs" />
@@ -239,6 +239,7 @@
<Compile Include="Utilities\LateBoundReflectionDelegateFactory.cs" />
<Compile Include="Utilities\LinqBridge.cs" />
<Compile Include="Utilities\MathUtils.cs" />
<Compile Include="Utilities\MethodBinder.cs" />
<Compile Include="Utilities\MethodCall.cs" />
<Compile Include="Utilities\MiscellaneousUtils.cs" />
<Compile Include="Utilities\PropertyNameTable.cs" />
@@ -228,6 +228,7 @@
<Compile Include="Utilities\DynamicReflectionDelegateFactory.cs" />
<Compile Include="Utilities\DynamicUtils.cs" />
<Compile Include="Utilities\JsonTokenUtils.cs" />
<Compile Include="Utilities\MethodBinder.cs" />
<Compile Include="Utilities\PropertyNameTable.cs" />
<Compile Include="Utilities\ReflectionObject.cs" />
<Compile Include="Utilities\EnumUtils.cs" />
@@ -55,7 +55,7 @@ namespace Newtonsoft.Json.Utilities
ILGenerator generator = dynamicMethod.GetILGenerator();
GenerateCreateMethodCallIL(method, generator, 0);
return (ObjectConstructor<object>)dynamicMethod.CreateDelegate(typeof(ObjectConstructor<object>));
}
@@ -90,7 +90,9 @@ namespace Newtonsoft.Json.Utilities
generator.PushInstance(method.DeclaringType);
}
int localVariableCount = 0;
LocalBuilder localConvertible = generator.DeclareLocal(typeof(IConvertible));
LocalBuilder localObject = generator.DeclareLocal(typeof(object));
int localVariableCount = 2;
for (int i = 0; i < args.Length; i++)
{
@@ -125,7 +127,7 @@ namespace Newtonsoft.Json.Utilities
generator.MarkLabel(skipSettingDefault);
generator.PushArrayInstance(argsIndex, i);
generator.UnboxIfNeeded(parameterType);
generator.Emit(OpCodes.Stloc, localVariableCount);
generator.Emit(OpCodes.Stloc_S, localVariable);
// parameter finished, we out!
generator.MarkLabel(finishedProcessingParameter);
@@ -133,7 +135,7 @@ namespace Newtonsoft.Json.Utilities
else
{
generator.UnboxIfNeeded(parameterType);
generator.Emit(OpCodes.Stloc, localVariableCount);
generator.Emit(OpCodes.Stloc_S, localVariable);
}
}
@@ -142,8 +144,9 @@ namespace Newtonsoft.Json.Utilities
localVariableCount++;
}
else if (parameterType.IsValueType())
{
{
generator.PushArrayInstance(argsIndex, i);
generator.Emit(OpCodes.Stloc_S, localObject);
// have to check that value type parameters aren't null
// otherwise they will error when unboxed
@@ -151,20 +154,59 @@ namespace Newtonsoft.Json.Utilities
Label finishedProcessingParameter = generator.DefineLabel();
// check if parameter is not null
generator.Emit(OpCodes.Ldloc_S, localObject);
generator.Emit(OpCodes.Brtrue_S, skipSettingDefault);
// parameter has no value, initialize to default
LocalBuilder localVariable = generator.DeclareLocal(parameterType);
generator.Emit(OpCodes.Ldloca_S, localVariable);
generator.Emit(OpCodes.Initobj, parameterType);
generator.Emit(OpCodes.Ldloc, localVariableCount);
generator.Emit(OpCodes.Ldloc_S, localVariable);
generator.Emit(OpCodes.Br_S, finishedProcessingParameter);
// parameter has value, get value from array again and unbox
// argument has value, try to convert it to parameter type
generator.MarkLabel(skipSettingDefault);
generator.PushArrayInstance(argsIndex, i);
generator.UnboxIfNeeded(parameterType);
if (parameterType.IsPrimitive())
{
// for primitive types we need to handle type widening (e.g. short -> int)
MethodInfo toParameterTypeMethod = typeof(IConvertible)
.GetMethod("To" + parameterType.Name, new[] { typeof(IFormatProvider) });
if (toParameterTypeMethod != null)
{
Label skipConvertible = generator.DefineLabel();
// check if argument type is an exact match for parameter type
// in this case we may use cheap unboxing instead
generator.Emit(OpCodes.Ldloc_S, localObject);
generator.Emit(OpCodes.Isinst, parameterType);
generator.Emit(OpCodes.Brtrue_S, skipConvertible);
// types don't match, check if argument implements IConvertible
generator.Emit(OpCodes.Ldloc_S, localObject);
generator.Emit(OpCodes.Isinst, typeof(IConvertible));
generator.Emit(OpCodes.Stloc_S, localConvertible);
generator.Emit(OpCodes.Ldloc_S, localConvertible);
generator.Emit(OpCodes.Brfalse_S, skipConvertible);
// convert argument to parameter type
generator.Emit(OpCodes.Ldloc_S, localConvertible);
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Callvirt, toParameterTypeMethod);
generator.Emit(OpCodes.Br_S, finishedProcessingParameter);
generator.MarkLabel(skipConvertible);
}
}
// we got here because either argument type matches parameter (conversion will succeed),
// or argument type doesn't match parameter, but we're out of options (conversion will fail)
generator.Emit(OpCodes.Ldloc_S, localObject);
generator.UnboxIfNeeded(parameterType);
// parameter finished, we out!
generator.MarkLabel(finishedProcessingParameter);
localVariableCount++;
@@ -105,18 +105,7 @@ namespace Newtonsoft.Json.Utilities
Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
Expression argExpression;
if (parameterType.IsValueType())
{
BinaryExpression ensureValueTypeNotNull = Expression.Coalesce(paramAccessorExpression, Expression.New(parameterType));
argExpression = EnsureCastExpression(ensureValueTypeNotNull, parameterType);
}
else
{
argExpression = EnsureCastExpression(paramAccessorExpression, parameterType);
}
Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef);
if (isByRef)
{
@@ -349,17 +338,41 @@ namespace Newtonsoft.Json.Utilities
Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
return compiled;
}
private Expression EnsureCastExpression(Expression expression, Type targetType)
private Expression EnsureCastExpression(Expression expression, Type targetType, bool allowWidening = false)
{
Type expressionType = expression.Type;
// check if a cast or conversion is required
if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType)))
{
return expression;
}
if (targetType.IsValueType())
{
Expression convert = Expression.Unbox(expression, targetType);
if (allowWidening && targetType.IsPrimitive())
{
MethodInfo toTargetTypeMethod = typeof(Convert)
.GetMethod("To" + targetType.Name, new[] { typeof(object) });
if (toTargetTypeMethod != null)
{
convert = Expression.Condition(
Expression.TypeIs(expression, targetType),
convert,
Expression.Call(toTargetTypeMethod, expression));
}
}
return Expression.Condition(
Expression.Equal(expression, Expression.Constant(null, typeof(object))),
Expression.Default(targetType),
convert);
}
return Expression.Convert(expression, targetType);
}
}
@@ -0,0 +1,319 @@
namespace Newtonsoft.Json.Utilities
{
#if PORTABLE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
internal static class MethodBinder
{
/// <summary>
/// List of primitive types which can be widened.
/// </summary>
private static readonly Type[] PrimitiveTypes = new Type[]
{
typeof(bool), typeof(char), typeof(sbyte), typeof(byte),
typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(float), typeof(double)
};
/// <summary>
/// Widening masks for primitive types above.
/// Index of the value in this array defines a type we're widening,
/// while the bits in mask define types it can be widened to (including itself).
///
/// For example, value at index 0 defines a bool type, and it only has bit 0 set,
/// i.e. bool values can be assigned only to bool.
/// </summary>
private static readonly int[] WideningMasks = new int[]
{
0x0001, 0x0FE2, 0x0D54, 0x0FFA,
0x0D50, 0x0FE2, 0x0D40, 0x0F80,
0x0D00, 0x0E00, 0x0C00, 0x0800
};
/// <summary>
/// Checks if value of primitive type <paramref name="from"/> can be
/// assigned to parameter of primitive type <paramref name="to"/>.
/// </summary>
/// <param name="from">Source primitive type</param>
/// <param name="to">Target primitive type</param>
/// <returns>True if source type can be widened to target type, false otherwise</returns>
private static bool CanConvertPrimitive(Type from, Type to)
{
if (from == to)
{
// same type
return true;
}
int fromMask = 0,
toMask = 0;
for (int i = 0; i < PrimitiveTypes.Length; i++)
{
if (PrimitiveTypes[i] == from)
{
fromMask = WideningMasks[i];
}
else if (PrimitiveTypes[i] == to)
{
toMask = 1 << i;
}
if (fromMask != 0 && toMask != 0)
{
break;
}
}
return (fromMask & toMask) != 0;
}
/// <summary>
/// Checks if a set of values with given <paramref name="types"/> can be used
/// to invoke a method with specified <paramref name="parameters"/>.
/// </summary>
/// <param name="parameters">Method parameters</param>
/// <param name="types">Argument types</param>
/// <param name="enableParamArray">Try to pack extra arguments into ParamArray</param>
/// <returns>True if method can be called with given arguments, false otherwise</returns>
private static bool FilterParameters(ParameterInfo[] parameters, IList<Type> types, bool enableParamArray)
{
ValidationUtils.ArgumentNotNull(parameters, nameof(parameters));
ValidationUtils.ArgumentNotNull(types, nameof(types));
if (parameters.Length == 0)
{
// fast check for parameterless methods
return types.Count == 0;
}
if (parameters.Length > types.Count)
{
// not all declared parameters were specified (optional parameters are not supported)
return false;
}
// check if the last parameter is ParamArray
Type paramArrayType = null;
if (enableParamArray)
{
ParameterInfo lastParam = parameters[parameters.Length - 1];
if (lastParam.ParameterType.IsArray && lastParam.IsDefined(typeof(ParamArrayAttribute)))
{
paramArrayType = lastParam.ParameterType.GetElementType();
}
}
if (paramArrayType == null && parameters.Length != types.Count)
{
// when there's no ParamArray, number of parameters should match
return false;
}
for (int i = 0; i < types.Count; i++)
{
Type paramType = (paramArrayType != null && i >= parameters.Length - 1) ? paramArrayType : parameters[i].ParameterType;
if (paramType == types[i])
{
// exact match with provided type
continue;
}
if (paramType == typeof(object))
{
// parameter of type object matches anything
continue;
}
if (paramType.IsPrimitive())
{
if (!types[i].IsPrimitive() || !CanConvertPrimitive(types[i], paramType))
{
// primitive parameter can only be assigned from compatible primitive type
return false;
}
}
else
{
if (!paramType.IsAssignableFrom(types[i]))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Compares two sets of parameters to determine
/// which one suits better for given argument types.
/// </summary>
private class ParametersMatchComparer : IComparer<ParameterInfo[]>
{
private readonly IList<Type> _types;
private readonly bool _enableParamArray;
public ParametersMatchComparer(IList<Type> types, bool enableParamArray)
{
ValidationUtils.ArgumentNotNull(types, nameof(types));
_types = types;
_enableParamArray = enableParamArray;
}
public int Compare(ParameterInfo[] parameters1, ParameterInfo[] parameters2)
{
ValidationUtils.ArgumentNotNull(parameters1, nameof(parameters1));
ValidationUtils.ArgumentNotNull(parameters2, nameof(parameters2));
// parameterless method wins
if (parameters1.Length == 0)
{
return -1;
}
if (parameters2.Length == 0)
{
return 1;
}
Type paramArrayType1 = null, paramArrayType2 = null;
if (_enableParamArray)
{
ParameterInfo lastParam1 = parameters1[parameters1.Length - 1];
if (lastParam1.ParameterType.IsArray && lastParam1.IsDefined(typeof(ParamArrayAttribute)))
{
paramArrayType1 = lastParam1.ParameterType.GetElementType();
}
ParameterInfo lastParam2 = parameters2[parameters2.Length - 1];
if (lastParam2.ParameterType.IsArray && lastParam2.IsDefined(typeof(ParamArrayAttribute)))
{
paramArrayType2 = lastParam2.ParameterType.GetElementType();
}
// A method using params always loses to one not using params
if (paramArrayType1 != null && paramArrayType2 == null)
{
return 1;
}
if (paramArrayType2 != null && paramArrayType1 == null)
{
return -1;
}
}
for (int i = 0; i < _types.Count; i++)
{
Type type1 = (paramArrayType1 != null && i >= parameters1.Length - 1) ? paramArrayType1 : parameters1[i].ParameterType;
Type type2 = (paramArrayType2 != null && i >= parameters2.Length - 1) ? paramArrayType2 : parameters2[i].ParameterType;
if (type1 == type2)
{
// exact match between parameter types doesn't change score
continue;
}
// exact match with source type decides winner immediately
if (type1 == _types[i])
{
return -1;
}
if (type2 == _types[i])
{
return 1;
}
int r = ChooseMorePreciseType(type1, type2);
if (r != 0)
{
// winner decided
return r;
}
}
return 0;
}
private static int ChooseMorePreciseType(Type type1, Type type2)
{
if (type1.IsByRef || type2.IsByRef)
{
if (type1.IsByRef && type2.IsByRef)
{
type1 = type1.GetElementType();
type2 = type2.GetElementType();
}
else if (type1.IsByRef)
{
type1 = type1.GetElementType();
if (type1 == type2)
{
return 1;
}
}
else
{
type2 = type2.GetElementType();
if (type2 == type1)
{
return -1;
}
}
}
bool c1FromC2, c2FromC1;
if (type1.IsPrimitive() && type2.IsPrimitive())
{
c1FromC2 = CanConvertPrimitive(type2, type1);
c2FromC1 = CanConvertPrimitive(type1, type2);
}
else
{
c1FromC2 = type1.IsAssignableFrom(type2);
c2FromC1 = type2.IsAssignableFrom(type1);
}
if (c1FromC2 == c2FromC1)
{
return 0;
}
return c1FromC2 ? 1 : -1;
}
}
/// <summary>
/// Retunrs a best method overload for given argument <paramref name="types"/>.
/// </summary>
/// <param name="candidates">List of method candidates</param>
/// <param name="types">Argument types</param>
/// <returns>Best method overload, or <c>null</c> if none matched</returns>
public static TMethod SelectMethod<TMethod>(IEnumerable<TMethod> candidates, IList<Type> types) where TMethod : MethodBase
{
ValidationUtils.ArgumentNotNull(candidates, nameof(candidates));
ValidationUtils.ArgumentNotNull(types, nameof(types));
// ParamArrays are not supported by ReflectionDelegateFactory
// They will be treated like ordinary array arguments
const bool enableParamArray = false;
return candidates
.Where(m => FilterParameters(m.GetParameters(), types, enableParamArray))
.OrderBy(m => m.GetParameters(), new ParametersMatchComparer(types, enableParamArray))
.FirstOrDefault();
}
}
#endif
}
+15 -38
View File
@@ -273,6 +273,7 @@ namespace Newtonsoft.Json.Utilities
}
#if !DOTNET
public static MethodInfo GetMethod(this Type type, string name)
{
return type.GetMethod(name, DefaultFlags);
@@ -295,21 +296,7 @@ namespace Newtonsoft.Json.Utilities
public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, object placeHolder1, IList<Type> parameterTypes, object placeHolder2)
{
return type.GetTypeInfo().DeclaredMethods.Where(
m =>
{
if (name != null && m.Name != name)
{
return false;
}
if (!TestAccessibility(m, bindingFlags))
{
return false;
}
return m.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes);
}).SingleOrDefault();
return MethodBinder.SelectMethod(type.GetTypeInfo().DeclaredMethods.Where(m => (name == null || m.Name == name) && TestAccessibility(m, bindingFlags)), parameterTypes);
}
public static IEnumerable<ConstructorInfo> GetConstructors(this Type type)
@@ -319,28 +306,9 @@ namespace Newtonsoft.Json.Utilities
public static IEnumerable<ConstructorInfo> GetConstructors(this Type type, BindingFlags bindingFlags)
{
return type.GetConstructors(bindingFlags, null);
return type.GetTypeInfo().DeclaredConstructors.Where(c => TestAccessibility(c, bindingFlags));
}
private static IEnumerable<ConstructorInfo> GetConstructors(this Type type, BindingFlags bindingFlags, IList<Type> parameterTypes)
{
return type.GetTypeInfo().DeclaredConstructors.Where(
c =>
{
if (!TestAccessibility(c, bindingFlags))
{
return false;
}
if (parameterTypes != null && !c.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes))
{
return false;
}
return true;
});
}
public static ConstructorInfo GetConstructor(this Type type, IList<Type> parameterTypes)
{
return type.GetConstructor(DefaultFlags, null, parameterTypes, null);
@@ -348,9 +316,9 @@ namespace Newtonsoft.Json.Utilities
public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object placeholder1, IList<Type> parameterTypes, object placeholder2)
{
return type.GetConstructors(bindingFlags, parameterTypes).SingleOrDefault();
return MethodBinder.SelectMethod(type.GetConstructors(bindingFlags), parameterTypes);
}
public static MemberInfo[] GetMember(this Type type, string member)
{
return type.GetMemberInternal(member, null, DefaultFlags);
@@ -573,6 +541,15 @@ namespace Newtonsoft.Json.Utilities
return type.GetTypeInfo().IsValueType;
#endif
}
public static bool IsPrimitive(this Type type)
{
#if !(DOTNET || PORTABLE)
return type.IsPrimitive;
#else
return type.GetTypeInfo().IsPrimitive;
#endif
}
public static bool AssignableToTypeName(this Type type, string fullTypeName, out Type match)
{