public ObjectStateInfo GetObjectState(object value)
        {
            Guard.EnsureIsNotNull("value", value);

            var type = value.GetType();
            var state = ExtractStateInfo(value, type);

            var stateInfo = new ObjectStateInfo
            {
                ObjectType = type
            };

            AssignObjectState(value, state, stateInfo, false);
            AssignChildObjectStates(value, state, stateInfo.ChildInfos);

            return stateInfo;
        }
        private void AssignChildObjectStates(object parent, InitialObjectState state, IList<ObjectStateInfo> childStateInfos)
        {
            if (childStateInfos.IsNull())
            {
                childStateInfos = new List<ObjectStateInfo>();
            }

            foreach (var childState in state.ChildObjectStates)
            {
                var childStateInfo = new ObjectStateInfo
                {
                    ObjectType = childState.ObjectType,
                    PropertyName = childState.PropertyName
                };

                AssignObjectState(parent, childState, childStateInfo, true);
                AssignChildState(childState, childStateInfo);

                childStateInfos.Add(childStateInfo);
            }
        }
        private void AssignObjectState(object item, InitialObjectState state, ObjectStateInfo stateInfo, bool isChild)
        {
            var value = GetValue(item, state, isChild);

            if (!InitialObjectStates.ContainsKey(state.Id))
            {
                stateInfo.ObjectState = ObjectState.New;
                return;
            }

            var stateAsParent = InitialObjectStates[state.Id];
            var stateAsChild = isChild ? GetChildInitialState(item, value) : null;

            if (stateAsParent.IsDeleted || (isChild && stateAsChild.IsNotNull() && stateAsChild.IsDeleted))
            {
                stateInfo.ObjectState = ObjectState.Deleted;
                return;
            }

            var hash = _hashHelper.GenerateHash(value);

            if (String.Compare(stateAsParent.HashCode, hash, StringComparison.InvariantCulture) != 0)
            {
                stateInfo.ObjectState = ObjectState.Updated;
                return;
            }

            stateInfo.ObjectState = ObjectState.NoChange;
            return;
        }
        private void AssignChildState(InitialObjectState childObjectState, ObjectStateInfo childStateInfo)
        {
            var foundAsParent = InitialObjectStates.ContainsKey(childObjectState.Id);
            var attachedToParent = false;

            if (InitialObjectStates.ContainsKey(childObjectState.ParentId))
            {
                var parentState = InitialObjectStates[childObjectState.ParentId];

                attachedToParent = parentState.ChildObjectStates
                    .Any(child => child.Id == childObjectState.Id);
            }

            var childState = AssignChildStateInternal(foundAsParent, attachedToParent);

            childStateInfo.ChildState = childState;
        }