比较C#中的动态对象

Mar*_*erg 13 c# dynamic

比较两个任意动态对象是否相同的最佳方法是什么?例如这两个对象.

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); // ?
Run Code Online (Sandbox Code Playgroud)

或者有没有办法将实际属性及其值作为列表?例如,从动态类型创建ExpandoObject?

dle*_*lev 12

ExpandoObject实现ICollection<KeyValuePair<string, object>>(除了IDictionaryIEnumerable相同),所以你应该能够很容易地通过属性比较它们的属性:

public static bool AreExpandosEquals(ExpandoObject obj1, ExpandoObject obj2)
{
    var obj1AsColl = (ICollection<KeyValuePair<string,object>>)obj1;
    var obj2AsDict = (IDictionary<string,object>)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;
}
Run Code Online (Sandbox Code Playgroud)


jbt*_*ule 9

当您没有编译器的帮助时,用于动态调用任意动态对象(IDynamicMetaObjectProvider)上的方法和属性的Microsoft API不容易使用.您可以使用Dynamitey(通过nuget)完全简化这一过程.它有一个静态函数 Dynamic.InvokeGet,只用一个目标和一个属性名来调用属性的getter.

要获取动态对象的属性列表,有一些问题,因为动态对象必须支持它(如果它是一个表示实现GetDynamicMemberNames的DynamicObject,则Expando支持它,但随机IDynamicMetaObjectProvider可能不会,只返回一个空列表).Dynamitey有一种简化获取这些名称的方法,Dynamic.GetMemberNames.

这两个函数都为您提供了通过属性比较许多任意动态对象所需的基本工具.

//using System.Dynamic;
//using Dynamitey;
//using System.Linq;

IEnumerable<string> list1 =Dynamic.GetMemberNames(obj1);
list1 = list1.OrderBy(m=>m);
IEnumerable<string> 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;
Run Code Online (Sandbox Code Playgroud)

但是,如果它们只是您自己的DynamicObject子类,那么仅仅遵循实现Equals的典型规则就更容易了,实际上与非动态对象没有区别,只是比较您在内部使用的状态.