diff --git a/Compare-NET-Objects-Tests/CompareClassTests.cs b/Compare-NET-Objects-Tests/CompareClassTests.cs index 8310a1e..55b4833 100644 --- a/Compare-NET-Objects-Tests/CompareClassTests.cs +++ b/Compare-NET-Objects-Tests/CompareClassTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using KellermanSoftware.CompareNetObjects; using KellermanSoftware.CompareNetObjectsTests.TestClasses; using NUnit.Framework; @@ -216,6 +217,44 @@ public void PrivateFieldInBaseClassNegative() } #endregion + #region Backing Field Tests + [Test] + public void BackingFieldPositive() + { + RecipeDetail detail1 = new RecipeDetail(true, "Toffee"); + detail1.Ingredient = "Crunchy Chocolate"; + + RecipeDetail detail2 = new RecipeDetail(true, "Crunchy Frogs"); + detail2.Ingredient = "Crunchy Chocolate"; + + _compare.Config.ComparePrivateFields = true; + _compare.Config.CompareBackingFields = false; + var result = _compare.Compare(detail1, detail2); + Assert.IsTrue(result.AreEqual); + Assert.IsTrue(result.Differences.Count == 0); + _compare.Config.ComparePrivateFields = false; + _compare.Config.CompareBackingFields = true; + } + + [Test] + public void BackingFieldNegative() + { + RecipeDetail detail1 = new RecipeDetail(true, "Toffee"); + detail1.Ingredient = "Crunchy Chocolate"; + + RecipeDetail detail2 = new RecipeDetail(true, "Crunchy Frogs"); + detail2.Ingredient = "Crunchy Chocolate"; + + _compare.Config.ComparePrivateFields = true; + _compare.Config.CompareBackingFields = true; + var result = _compare.Compare(detail1, detail2); + Assert.IsFalse(result.AreEqual); + Assert.IsTrue(result.Differences.Any(dif => dif.PropertyName == "k__BackingField")); + _compare.Config.ComparePrivateFields = false; + _compare.Config.CompareBackingFields = true; + } + #endregion + #endif #region InterfaceMembers diff --git a/Compare-NET-Objects/Cache.cs b/Compare-NET-Objects/Cache.cs index 80f2546..42399c4 100644 --- a/Compare-NET-Objects/Cache.cs +++ b/Compare-NET-Objects/Cache.cs @@ -68,35 +68,46 @@ public static IEnumerable GetFieldInfo(ComparisonConfig config, Type FieldInfo[] currentFields; #if !NETSTANDARD1_3 - //All the implementation examples that I have seen for dynamic objects use private fields or properties - if (( config.ComparePrivateFields || isDynamicType) && !config.CompareStaticFields) + BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; + if (config.ComparePrivateFields || isDynamicType) { - List list = new List(); - Type t = type; - do - { - list.AddRange(t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)); - t = t.BaseType; - } while (t != null); - currentFields = list.ToArray(); + flags |= BindingFlags.NonPublic; } - else if ((config.ComparePrivateFields || isDynamicType) && config.CompareStaticFields) + if (config.CompareStaticFields) { - List list = new List(); - Type t = type; - do - { - list.AddRange( - t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | - BindingFlags.Static)); - t = t.BaseType; - } while (t != null); - currentFields = list.ToArray(); + flags |= BindingFlags.Static; } - else -#endif - currentFields = type.GetFields(); //Default is public instance and static + Func fieldIsBacking = field => field.Name.Contains("k__BackingField"); + List list = new List(); + Type t = type; + do + { + foreach (var field in t.GetFields(flags)) + { + if (!config.ComparePrivateFields) + { + list.Add(field); + } + else if (config.ComparePrivateFields && !config.CompareBackingFields && !fieldIsBacking(field)) + { + list.Add(field); + } + else if (config.ComparePrivateFields && config.CompareBackingFields) + { + list.Add(field); + } + else if (isDynamicType) + { + list.Add(field); + } + } + t = t.BaseType; + } while (t != null); + currentFields = list.ToArray(); +#else + currentFields = type.GetFields(); //Default is public instance and static +#endif if (config.Caching) _fieldCache.Add(type, currentFields); diff --git a/Compare-NET-Objects/ComparisonConfig.cs b/Compare-NET-Objects/ComparisonConfig.cs index 75ee494..410dc30 100644 --- a/Compare-NET-Objects/ComparisonConfig.cs +++ b/Compare-NET-Objects/ComparisonConfig.cs @@ -316,6 +316,16 @@ public void CustomPropertyComparer(Expression> cust public bool ComparePrivateFields { get; set; } #endif +#if !NETSTANDARD1_3 + /// + /// If true and true, then backing fields will be compared. The default is true. Silverlight and WinRT restricts access to private variables. + /// +#if !NETSTANDARD + [DataMember] +#endif + public bool CompareBackingFields { get; set; } +#endif + /// /// If true, static properties will be compared. The default is true. /// @@ -643,6 +653,7 @@ public void Reset() #if !NETSTANDARD1_3 ComparePrivateProperties = false; ComparePrivateFields = false; + CompareBackingFields = true; #endif CustomPropertyComparers = new Dictionary(); CompareChildren = true;