I have a model class Class1 and I want to compare if two instances of Class1 are same (structural equality).
public class Class1 : IEquatable<Class1>
{
    public string Id { get; set; }
    public string Name { get; set; }
    public IList<Class2> Class2s { get; set; }
    public bool Equals(Class1 other)
    {
       return QuestName.Equals(other.QuestName)
            && Class2s.OrderBy(c => c.Id).SequenceEqual(other.Class2s.OrderBy(c => c.Id));
                    //Below method is very fast but not so accurate
                    //because 2 objects with the same hash code may or may not be equal
        //return GetHashCode() == other.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return obj is Class1
            && this.Equals(obj as Class1);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 13;
            hash = (hash * 7) + Name.GetHashCode();
            foreach (var c2 in Class2s.OrderBy(c => c.Id))
            {
                hash = (hash * 7) + c2.GetHashCode();
            }
            return hash;
        }
    }
}
public class Class2 : IEquatable<Class2>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Class3> Class3s { get; set; }
    public bool Equals(Class2 other)
    {
        return Id == other.Id
             && Name.Equals(other.Name)
             && Class3s.OrderBy(c => c.Id).SequenceEqual(other.Class3s.OrderBy(c => c.Id));
    }
    public override bool Equals(object obj)
    {
        return obj is Class2
            && this.Equals(obj as Class2 );
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 13;
            hash = (hash * 7) + Id.GetHashCode();
            hash = (hash * 7) + Name.GetHashCode();
            foreach (var c3 in Class3s.OrderBy(c => c.Id))
            {
                hash = (hash * 7) + c3.GetHashCode();
            }
            return hash;
        }
    }
}
public class Class3 : IEquatable<Class3>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Class4> Class4s { get; set; }
    public bool Equals(Class3 other)
    {
        return Id == other.Id
            && Name.Equals(other.Name)
            && Class4s.OrderBy(c => c.Id).SequenceEqual(other.Class4s.OrderBy(c => c.Id));
    }
    public override bool Equals(object obj)
    {
        return obj is Class3
            && this.Equals(obj as Class3);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 13;
            hash = (hash * 7) + Id.GetHashCode();
            hash = (hash * 7) + Name.GetHashCode();
            foreach (var c in Class4s.OrderBy(c => c.Id))   
            {
                hash = (hash * 7) + c.GetHashCode();
            }                
            return hash;
        }
    }
}
public class Class4 : IEquatable<Class4>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Equals(Class4 other)
    {
        return Id.Equals(other.Id)
            && Name.Equals(other.Name);
    }
    public override bool Equals(object obj)
    {
        return obj is Class4
            && this.Equals(obj as Class4);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 13;
            hash = (hash * 7) + Id.GetHashCode();
            hash = (hash * 7) + Name.GetHashCode();
            return hash;
        }
    }
}
I say that two Class1 objects are equal when:
1. they have the same Name
2. they have the same Class2 objects (their order does not matter)
Two Class2 objects are equal:
1. They have the same Id
2. They Have the same name
3. they have the same Class3 objects (their order does not matter)  
Two Class3 objects are equal:
1. They have the same Id
2. They Have the same name
3. they have the same Class4 objects (their order does not matter)   
Two Class4 objects are equal:
1. They ave the same Id
2. They Have the same name  
I compare them using the Equals method and measure the run time like this:
Class1 obj1 = GetFirstClass1Object();
Class1 obj2 = GetSecondClass1Object();
var startTime = DateTime.Now;
bool equals = obj1.Equals(obj2);
var elaspedTime = DateTime.Now.Substract(startTime)
the above solution works just fine but it's very slow. 
I know that if we flatten obj1 and obj2, they contain 3500 Class4 objects each and it takes around 12 seconds to compare obj1 and obj2.
Is there any faster way to do this? Can I somehow make use of hashing to make this faster?
Also, the number of Class2, Class3 and Class4 objects inside both obj1 and obj2 will always be same
 
     
     
     
     
    