diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs index 4565e430..0afb98a5 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs @@ -35,6 +35,13 @@ using System.Text; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Newtonsoft.Json.Utilities; +#if !PORTABLE +using MemberTypes = System.Reflection.MemberTypes; +using BindingFlags = System.Reflection.BindingFlags; +#else +using MemberTypes = Newtonsoft.Json.Utilities.MemberTypes; +using BindingFlags = Newtonsoft.Json.Utilities.BindingFlags; +#endif namespace Newtonsoft.Json.Tests.Benchmarks { @@ -89,6 +96,19 @@ namespace Newtonsoft.Json.Tests.Benchmarks decimal.TryParse(FloatText, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out value); } + [Benchmark] + public void GetMemberWithMemberTypeAndBindingFlags() + { + typeof(LowLevelBenchmarks).GetMember("AName", MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + } + + [Benchmark] + public void GetPropertyGetField() + { + typeof(LowLevelBenchmarks).GetProperty("AName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + typeof(LowLevelBenchmarks).GetField("AName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + } + [Benchmark] public void DecimalTryParseChars() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index ed55bca6..9b499ec8 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -650,5 +650,116 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.IsTrue(extensionData.Any()); Assert.IsTrue(extensionData.Any()); // second test fails if the enumerator returned isn't reset } + + public class ClassWithShouldSerialize + { + public string Prop1 { get; set; } + public string Prop2 { get; set; } + + public bool ShouldSerializeProp1() + { + return false; + } + } + + [Test] + public void DefaultContractResolverIgnoreShouldSerializeTrue() + { + DefaultContractResolver resolver = new DefaultContractResolver(); + resolver.IgnoreShouldSerializeMembers = true; + + JsonObjectContract contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithShouldSerialize)); + + var property1 = contract.Properties["Prop1"]; + Assert.AreEqual(null, property1.ShouldSerialize); + + var property2 = contract.Properties["Prop2"]; + Assert.AreEqual(null, property2.ShouldSerialize); + } + + [Test] + public void DefaultContractResolverIgnoreShouldSerializeUnset() + { + DefaultContractResolver resolver = new DefaultContractResolver(); + + JsonObjectContract contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithShouldSerialize)); + + var property1 = contract.Properties["Prop1"]; + Assert.AreNotEqual(null, property1.ShouldSerialize); + + var property2 = contract.Properties["Prop2"]; + Assert.AreEqual(null, property2.ShouldSerialize); + } + + public class ClassWithIsSpecified + { + [JsonProperty] + public string Prop1 { get; set; } + [JsonProperty] + public string Prop2 { get; set; } + [JsonProperty] + public string Prop3 { get; set; } + [JsonProperty] + public string Prop4 { get; set; } + + public bool Prop1Specified; + public bool Prop2Specified { get; set; } + public static bool Prop3Specified { get; set; } + public event System.Func Prop4Specified; + + protected virtual bool OnProp4Specified() + { + return Prop4Specified?.Invoke() ?? false; + } + } + + [Test] + public void DefaultContractResolverIgnoreIsSpecifiedTrue() + { + DefaultContractResolver resolver = new DefaultContractResolver(); + resolver.IgnoreIsSpecifiedMembers = true; + + JsonObjectContract contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithIsSpecified)); + + var property1 = contract.Properties["Prop1"]; + Assert.AreEqual(null, property1.GetIsSpecified); + Assert.AreEqual(null, property1.SetIsSpecified); + + var property2 = contract.Properties["Prop2"]; + Assert.AreEqual(null, property2.GetIsSpecified); + Assert.AreEqual(null, property2.SetIsSpecified); + + var property3 = contract.Properties["Prop3"]; + Assert.AreEqual(null, property3.GetIsSpecified); + Assert.AreEqual(null, property3.SetIsSpecified); + + var property4 = contract.Properties["Prop4"]; + Assert.AreEqual(null, property4.GetIsSpecified); + Assert.AreEqual(null, property4.SetIsSpecified); + } + + [Test] + public void DefaultContractResolverIgnoreIsSpecifiedUnset() + { + DefaultContractResolver resolver = new DefaultContractResolver(); + + JsonObjectContract contract = (JsonObjectContract)resolver.ResolveContract(typeof(ClassWithIsSpecified)); + + var property1 = contract.Properties["Prop1"]; + Assert.AreNotEqual(null, property1.GetIsSpecified); + Assert.AreNotEqual(null, property1.SetIsSpecified); + + var property2 = contract.Properties["Prop2"]; + Assert.AreNotEqual(null, property2.GetIsSpecified); + Assert.AreNotEqual(null, property2.SetIsSpecified); + + var property3 = contract.Properties["Prop3"]; + Assert.AreEqual(null, property3.GetIsSpecified); + Assert.AreEqual(null, property3.SetIsSpecified); + + var property4 = contract.Properties["Prop4"]; + Assert.AreEqual(null, property4.GetIsSpecified); + Assert.AreEqual(null, property4.SetIsSpecified); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index d4fde5d2..23ade6b5 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -155,6 +155,14 @@ namespace Newtonsoft.Json.Serialization /// public bool IgnoreIsSpecifiedMembers { get; set; } + /// + /// Gets or sets a value indicating whether to ignore ShouldSerialize members when serializing and deserializing tyeps. + /// + /// + /// true if the ShouldSerialize members will be ignored when serializing and deserializing types; otherwise, false. + /// + public bool IgnoreShouldSerializeMembers { get; set; } + /// /// Gets or sets the naming strategy used to resolve how property names and dictionary keys are serialized. /// @@ -1393,7 +1401,11 @@ namespace Newtonsoft.Json.Serialization property.Readable = true; property.Writable = true; } - property.ShouldSerialize = CreateShouldSerializeTest(member); + + if (!IgnoreShouldSerializeMembers) + { + property.ShouldSerialize = CreateShouldSerializeTest(member); + } if (!IgnoreIsSpecifiedMembers) { diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 03a445df..ce05b509 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -44,13 +44,13 @@ using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Utilities { #if (DOTNET || PORTABLE || PORTABLE40) + [Flags] internal enum MemberTypes { - Property = 0, - Field = 1, Event = 2, - Method = 3, - Other = 4 + Field = 4, + Method = 8, + Property = 16 } #endif diff --git a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs index 7467f63c..b7e1a7f3 100644 --- a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs +++ b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs @@ -128,7 +128,7 @@ namespace Newtonsoft.Json.Utilities } else { - return MemberTypes.Other; + return default(MemberTypes); } #endif } @@ -248,7 +248,7 @@ namespace Newtonsoft.Json.Utilities #else return type.GetMember(name, bindingFlags).Where(m => { - if (m.MemberType() != memberType) + if ((m.MemberType() | memberType) != memberType) { return false; } @@ -334,7 +334,7 @@ namespace Newtonsoft.Json.Utilities return type.GetTypeInfo().GetMembersRecursive().Where(m => m.Name == member && // test type before accessibility - accessibility doesn't support some types - (memberType == null || m.MemberType() == memberType) && + (memberType == null || (m.MemberType() | memberType) == memberType) && TestAccessibility(m, bindingFlags)).ToArray(); }