From d4c6a8de2605e59be18cf2f0dbeb3e9bb604719e Mon Sep 17 00:00:00 2001 From: JamesNK Date: Sat, 16 Aug 2008 07:34:54 +0000 Subject: [PATCH] -Fix GetFieldsAndProperties so that it returns a distinct list of member names in cases where there are overriden abstract generic properties --- .../JsonSerializerTest.cs | 17 +++++++++ .../Utilities/ReflectionUtils.cs | 37 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs index 4c8377e3..d8e4a73a 100644 --- a/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonSerializerTest.cs @@ -1264,5 +1264,22 @@ keyword such as type of business."" IncompatibleJsonAttributeClass c = new IncompatibleJsonAttributeClass(); JavaScriptConvert.SerializeObject(c); } + + public abstract class AbstractGenericBase + { + public abstract TKey Id { get; set; } + } + + public class GenericImpl : AbstractGenericBase + { + public override int Id { get; set; } + } + + [Test] + public void GenericAbstractProperty() + { + string json = JavaScriptConvert.SerializeObject(new GenericImpl()); + Assert.AreEqual(@"{""Id"":0}", json); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index 27eae652..c0b5ab10 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -471,7 +471,42 @@ namespace Newtonsoft.Json.Utilities targetMembers.AddRange(type.GetFields(bindingAttr)); targetMembers.AddRange(type.GetProperties(bindingAttr)); - return targetMembers; + // for some reason .NET returns multiple members when overriding a generic member on a base class + // http://forums.msdn.microsoft.com/en-US/netfxbcl/thread/b5abbfee-e292-4a64-8907-4e3f0fb90cd9/ + // filter members to only return the overriden member on the topmost class + List distinctMembers = new List(targetMembers.Count); + + var groupedMembers = targetMembers.GroupBy(m => m.Name).Select(g => new { Count = g.Count(), Members = g.Cast() }); + foreach (var groupedMember in groupedMembers) + { + if (groupedMember.Count == 1) + distinctMembers.Add(groupedMember.Members.First()); + else + distinctMembers.Add(groupedMember.Members.Where(m => !IsOverridenGenericMember(m, bindingAttr)).First()); + } + + return distinctMembers; + } + + private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags bindingAttr) + { + if (memberInfo.MemberType != MemberTypes.Field && memberInfo.MemberType != MemberTypes.Property) + throw new ArgumentException("Member must be a field or property."); + + Type declaringType = memberInfo.DeclaringType; + if (!declaringType.IsGenericType) + return false; + Type genericTypeDefinition = declaringType.GetGenericTypeDefinition(); + if (genericTypeDefinition == null) + return false; + MemberInfo[] members = genericTypeDefinition.GetMember(memberInfo.Name, bindingAttr); + if (members.Length == 0) + return false; + Type memberUnderlyingType = GetMemberUnderlyingType(members[0]); + if (!memberUnderlyingType.IsGenericParameter) + return false; + + return true; } public static T GetAttribute(ICustomAttributeProvider attributeProvider) where T : Attribute