Comparing dynamic objects in C#

前端 未结 6 2316
不知归路
不知归路 2021-02-13 04:08

What is the best way to compare two arbitrary dynamic objects for equality? For example these two objects.

I.e.

dynamic obj1 = new ExpandoObject();
obj1.         


        
相关标签:
6条回答
  • 2021-02-13 04:10

    ExpandoObject implements ICollection<KeyValuePair<string, object>> (in addition to IDictionary and IEnumerable of the same), so you should be able to compare them property by property pretty easily:

    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;
    }
    
    0 讨论(0)
  • 2021-02-13 04:10

    See "Enumerating and deleting members" to get the members of an ExpandoObject http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx

    Arbitrary dynamic objects do not appear to expose enumerators, though.

    0 讨论(0)
  • 2021-02-13 04:10

    Expando Objects are useable as an IDictonary<string, object> so you should be able to use that.

    Something like

    Assert.AreEqual((IDictonary(object, string))obj1, (IDictonary(object, string))obj2); 
    

    Edit the AreEqual won't work.

    But you could try comparing the two dictionaries fairly simply.

    0 讨论(0)
  • 2021-02-13 04:22

    You can also use the ObjectsComparer library available on GitHub : ObjectsComparer

    This library is an object-to-object comparer that allows us to compare objects recursively member by member and to define custom comparison rules for certain properties, fields or types. It supports enumerables (arrays, collections, lists), multidimensional arrays, enumerations, flags and dynamic objects (ExpandoObject, DynamicObject and compiler generated dynamic objects).

    Go to Valerii Tereshchenko excellent paper for more details.

    0 讨论(0)
  • 2021-02-13 04:32

    The Microsoft API's for dynamically invoking methods and propertys on arbitrary dynamic objects (IDynamicMetaObjectProvider) are not easy to use when you don't have the compiler's help. You can use Dynamitey (via nuget) to simplify this completely. It has a static function Dynamic.InvokeGet to call property's getters with just a target and a property name.

    To get a list of properties of the dynamic object, there is a bit of a gotcha, as the dynamic object has to support it (if it's a DynamicObject that means implementing GetDynamicMemberNames, Expando supports it, but random IDynamicMetaObjectProvider may not and just return an empty list). Dynamitey has a method to simplifying getting those names as well, Dynamic.GetMemberNames.

    Both of those two functions give you the basic tools necessary to compare many arbitrary dynamic objects via properties.

    //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;
    

    However, if they are just your own DynamicObject subclass then it'd be easier to just follow the typical rules for implementing Equals, there really is no difference from non-dynamic objects, and just compare what you are internally using for state.

    0 讨论(0)
  • 2021-02-13 04:34

    You have to implement IComparable-Interface. Then you have the appropriate functions needed from .NET/C# to compare two objects with each other.

    0 讨论(0)
提交回复
热议问题