比较C#中的动态对象
比较两个任意动态对象是否相同的最佳方法是什么? 例如这两个对象。
即
dynamic obj1 = new ExpandoObject(); obj1.Name = "Marcus"; obj1.Age = 39; obj1.LengthInMeters = 1.96; dynamic obj2 = AMethodReturningADynamic(); obj2.Name = "Marcus"; obj2.Age = 39; obj2.LengthInMeters = 1.96; Assert.AreEqual(obj1, obj2); // ?
或者有没有办法将实际属性及其值作为列表? 例如,从动态类型创建ExpandoObject?
当您没有编译器的帮助时,用于动态调用任意动态对象(IDynamicMetaObjectProvider)上的方法和属性的Microsoft API不容易使用。 您可以使用Dynamitey (通过nuget)完全简化此操作。 它有一个静态函数Dynamic.InvokeGet ,只用一个目标和一个属性名来调用属性的getter。
要获取动态对象的属性列表,有一些问题,因为动态对象必须支持它(如果它是一个表示实现GetDynamicMemberNames的DynamicObject,则Expando支持它,但随机IDynamicMetaObjectProvider可能不会,只返回一个空列表)。 Dynamitey有一种简化获取这些名称的方法, Dynamic.GetMemberNames 。
这两个函数都为您提供了通过属性比较许多任意动态对象所需的基本工具。
//using System.Dynamic; //using Dynamitey; //using System.Linq; IEnumerable list1 =Dynamic.GetMemberNames(obj1); list1 = list1.OrderBy(m=>m); IEnumerable list2 =Dynamic.GetMemberNames(obj2); list2 = list2.OrderBy(m=>m); if(!list1.SequenceEqual(list2)) return false; foreach(var memberName in list1){ if(!Dynamic.InvokeGet(obj1, memberName).Equals(Dynamic.InvokeGet(obj2,memberName))){ return false; } } return true;
但是,如果它们只是您自己的DynamicObject子类,那么仅仅遵循实现Equals的典型规则就更容易了,实际上与非动态对象没有区别,只是比较您在内部使用的状态。
ExpandoObject
实现ICollection
(除了IDictionary
和IEnumerable
之外),因此您应该能够非常轻松地按属性比较它们:
public static bool AreExpandosEquals(ExpandoObject obj1, ExpandoObject obj2) { var obj1AsColl = (ICollection>)obj1; var obj2AsDict = (IDictionary)obj2; // Make sure they have the same number of properties if (obj1AsColl.Count != obj2AsDict.Count) return false; foreach (var pair in obj1AsColl) { // Try to get the same-named property from obj2 object o; if (!obj2AsDict.TryGetValue(pair.Key, out o)) return false; // Property names match, what about the values they store? if (!object.Equals(o, pair.Value)) return false; } // Everything matches return true; }
您必须实现IComparable -Interface。 然后,您将拥有.NET / C#所需的相应function,以便将两个对象相互比较。
请参阅“枚举和删除成员”以获取ExpandoObject的成员http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx
但是,任意动态对象似乎不会暴露枚举器。
Expando对象可用作IDictonary
因此您应该能够使用它。
就像是
Assert.AreEqual((IDictonary(object, string))obj1, (IDictonary(object, string))obj2);
编辑 AreEqual
将无法正常工作。
但你可以尝试相当简单地比较两个词典。
- 是否有.NET Framework方法将文件URI转换为带有驱动器号的路径?
- 用Unity填充集合的方法
- 将varchar数据类型转换为日期时间数据类型会导致超出范围的值错误
- 无法加载文件或程序集’System.IdentityModel,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089’或其依赖项之一
- 如何定义路由中的PUT方法仅限于没有参数的控制器中的Put方法?
- DateTime解析错误:提供的DateTime表示无效时间
- 如何在自定义validation中调用默认的ServerCertificateValidationCallback?
- 烦人的SQLexception,可能是由于某些代码做错了
- DataGridComboBoxColumn用于不同行的不同ItemsSource