StevenGilligan/AutoCompare

Can't compare list of objects - System.Security.VerificationException

Opened this issue · 2 comments

Passing a list of objects (or even value types, like INTs) to the Compare method results in a System.Security.VerificationException: "Operation count destabilize the runtime."

Stack trace:

   at lambda_method(Closure , List`1 , List`1 )
   at AutoCompare.Engine.Compare[T](T oldObject, T newObject)
   at ConsoleApplication1.Program.Main(String[] args) in C:\Users\<userName>\documents\visual studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line 82
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

This can be reproduced by using the following code:

public class MyObject
{
        public bool MyProperty { get; set; }
}

class Program
{
        static void Main(string[] args)
        {
                var list1 = new List<MyObject> {new MyObject() };
                var list2 = new List<MyObject>();
                var engine = new AutoCompare.Engine();
                engine.Configure<List<MyObject>>().Compile.Now();
                var differences = engine.Compare(list1, list2);
        }
}

Side note:

I came across this issue because I have a list of objects that derive from a common base class in an object I'm trying to compare, like this:

List<BaseClass> list = new List<BaseClass>();
list,Add(new DerivedClass1());
list.Add(new DerivedClass2());

This library works great at finding the differences of the objects for the base class properties, but doesn't compare the derived ones.

I can think of two options for this:

  • Pass a list that contains just objects of each of the derived types. This would mean several calls, but it's doable. Unfortunately, this causes the Exception in this issue. I could create a 'helper' object that only contains a List, but this feels a bit clunky.
  • Have AutoCompare detect the underlying types of the objects, and compare all of the properties. This might be more complex than necessary. Assuming two objects match via the ID, does it make sense to then check the type, and if it's the same, THEN use all public properties? If it's not the same, fall back to just base class properties? That's why I was leaning toward the first option, but I'd be willing to talk about the second.

As of right now, the engine.Compare<T>(T a, T b) method cannot handle Enumerables or Collections.

This is one of the reason why I haven't bumped AutoCompare to V1.0 yet because I feel like I need to change the inner workings of the library to support this before I can call put a 1.0 label on it, since I need to do a pretty big refactor of the internals for this to work. I have already started the work on my local dev, but it's still far from being completed.

As a workaround for now, you should handle the list yourself and compare each elements, then aggregate the list of differences. Ex:

public class MyObject
{
    public bool MyProperty { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var list1 = new List<MyObject> { new MyObject() { MyProperty = true } };
        var list2 = new List<MyObject> { new MyObject() { MyProperty = false } };
        var engine = new AutoCompare.Engine();
        engine.Configure<MyObject>().Compile.Now();
        var comparer = engine.Get<MyObject>();
        var differences = list1.Zip(list2, (a, b) => comparer(a, b)).SelectMany(x => x);
    }
}

Hi, is this project still alive?