/// <summary> /// Obtains the common default properties for multiple objects</summary> /// <param name="items">Items with properties</param> /// <returns>Default properties all shared by multiple objects</returns> /// <remarks>Some of the descriptors may be MultiPropertyDescriptor so that all the items can share them.</remarks> public static IEnumerable<PropertyDescriptor> GetSharedProperties(IEnumerable<object> items) { List<PropertyDescriptor> result = new List<PropertyDescriptor>(); bool firstTime = true; foreach (object item in items) { IEnumerable<PropertyDescriptor> properties = GetDefaultProperties(item).Cast<PropertyDescriptor>(); if (firstTime) { firstTime = false; result.AddRange(properties); } else { for (int i = 0; i < result.Count; ) { string key = GetPropertyDescriptorKey(result[i]); // Check the item for a matching property descriptor // If found: replace normal descriptor with MultiPropertyDescriptor in the result // Otherwise: Remove the property from merged properties PropertyDescriptor matchingDescriptor = FindPropertyDescriptor(item, key); if (matchingDescriptor != null) { var multiDescriptor = result[i] as MultiPropertyDescriptor; if (multiDescriptor == null) { multiDescriptor = new MultiPropertyDescriptor(result[i]); result[i] = multiDescriptor; } i++; } else result.RemoveAt(i); } } } return result; }
public void TestGetPropertyDescriptorKey() { // First use AttributePropertyDescriptor and MultiPropertyDescriptor { // Make sure that different property descriptor objects with the same Name, Category and Type // have the same hash code, using PropertyUtils.GetPropertyDescriptorHash(). var attrPropertyDescriptor = new AttributePropertyDescriptor( "TestName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), "TestCategory", "Test description", false); var multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor); Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor)); // Make sure that null Category names work, too. attrPropertyDescriptor = new AttributePropertyDescriptor( "TestName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), null, "Test description", false); multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor); Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor)); // Make sure that if the Name and Category and identical, that it works with other property // descriptors who also have identical Name and Category strings. This makes sure that we // are not using 'xor' between the Name and Category. attrPropertyDescriptor = new AttributePropertyDescriptor( "SameName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), "SameName", "Name and Category are the same!", false); multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor); Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor)); var d2 = new AttributePropertyDescriptor( "AnotherSameName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), "AnotherSameName", "Name and Category are the same!", false); var m2 = new MultiPropertyDescriptor(d2); Assert.IsTrue(IsSameHashKey(d2, m2)); Assert.IsTrue(!IsSameHashKey(attrPropertyDescriptor, d2)); // Make sure that if the Name and Category are swapped, that they yield different codes. attrPropertyDescriptor = new AttributePropertyDescriptor( "Name1", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), "Name2", "Test description", false); d2 = new AttributePropertyDescriptor( "Name2", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))), "Name1", "Test description", false); Assert.IsTrue(!IsSameHashKey(attrPropertyDescriptor, d2)); } // Now use a stub property descriptor and MultiPropertyDescriptor { // Make sure that different property descriptor objects with the same Name, Category and Type // have the same hash code, using PropertyUtils.GetPropertyDescriptorHash(). var stubPropertyDescriptor = new MyPropertyDescriptor("TestName", "TestCategory", typeof(string)); var multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor); Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor)); // Make sure that null Category names work, too. stubPropertyDescriptor = new MyPropertyDescriptor("TestName", null, typeof(string)); multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor); Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor)); // Make sure that if the Name and Category and identical, that it works with other property // descriptors who also have identical Name and Category strings. This makes sure that we // are not using 'xor' between the Name and Category. stubPropertyDescriptor = new MyPropertyDescriptor("SameName", "SameName", typeof(string)); multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor); Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor)); var d2 = new MyPropertyDescriptor("AnotherSameName", "AnotherSameName", typeof(string)); var m2 = new MultiPropertyDescriptor(d2); Assert.IsTrue(IsSameHashKey(d2, m2)); Assert.IsTrue(!IsSameHashKey(stubPropertyDescriptor, d2)); // Make sure that if the Name and Category are swapped, that they yield different codes. stubPropertyDescriptor = new MyPropertyDescriptor("Name1", "Name2", typeof(string)); d2 = new MyPropertyDescriptor("Name2", "Name1", typeof(string)); Assert.IsTrue(!IsSameHashKey(stubPropertyDescriptor, d2)); } }