3

I have some classes of objects that should by design originate from remote assemblies. I would like to be able to compare instances of these classes for equality even if the instances are loaded from different assemblies. In real life these would be loaded from network locations or the web and I would like to compare with a local cache. I have some good results from a solution that uses serialization and a custom serialization binder.

The sample client code I am using to make the comparison is:

    Assembly a = Assembly.LoadFile(@"c:\work\abc1\abc.dll");
    Type t1 = a.GetType("Abc.Def");
    Assembly b = Assembly.LoadFile(@"c:\work\abc2\abc.dll");
    Type t2 = b.GetType("Abc.Def");
    Object o1 = t1.GetConstructors()[0].Invoke(null);
    Object o2 = t2.GetConstructors()[0].Invoke(null);
    Console.WriteLine(o1.Equals(o2));

The pattern I am using in my assembly is:

namespace Abc
{
    internal sealed class DefBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Type ttd = null;
            try
            {
                ttd = this.GetType().Assembly.GetType(typeName);
            }
            catch (Exception any)
            {
                Debug.WriteLine(any.Message);
            }
            return ttd;
        }
    }


    [Serializable]
    public class Def
    {
        public Def()
        {
            Data = "This is the data";
        }
        public String Data { set; get; }
        public override bool Equals(object obj)
        {
            if (obj.GetType().FullName.Equals(this.GetType().FullName))
            {
                try
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    System.IO.MemoryStream ms = new System.IO.MemoryStream();
                    bf.Serialize(ms, obj);
                    ms.Seek(0, System.IO.SeekOrigin.Begin);
                    bf.Binder = new Abc.DefBinder();
                    Abc.Def that = (Abc.Def)bf.Deserialize(ms);
                    if (this.Data.Equals(that.Data))
                    {
                        return true;
                    }
                }
                catch (Exception any) {
                    Debug.WriteLine(any.Message);
                }
            }
            return false;
        }
    }
}

My question is: This seems to work but it feels hacky, so is there a more direct way to compare objects that might be loaded from different assemblies?

Mishax
  • 4,442
  • 5
  • 39
  • 63
  • Does [this link](http://stackoverflow.com/questions/411232/comparing-two-objects) help? – Kaf Nov 21 '12 at 20:31

1 Answers1

1

That is somewhat hacky but is a quick and easy way to get the job done. Another thing you could do is use a lot of reflection to write an equality method for two given types. Something like:

public bool Equals(Type t1, Type t2)
{
    var t1Constructors = t1.GetConstructors();
    var t2Constructors = t2.GetConstructors();
    //compare constructors
    var t1Methods = t1.GetMethods();
    var t2Methods = t2.GetMethods();
    //compare methods
    //etc.
}

and so on, using BindingFlags to get properties/methods/etc. that you care about and inspecting each for equality. Certainly not exactly easy but it would give you a lot of flexibility about determining what "equality" really means in your specific use case.

Evan Phillips
  • 261
  • 2
  • 4
  • Evan, I was about to quip something about this not being a workable solution since I would also need to have access to private members. I went ahead and tested it anyway and am COMPLETELY AMAZED that I can use reflection not only to discover private members but also INVOKE THEM from a completely different class. How is this possible? I had no idea! – Mishax Nov 23 '12 at 10:04