예제 #1
0
        private static void ScanForChanges(ContextPair contextPair, ObjectPath objectPath, ChangeCollection result)
        {
            var pathType = GetTypeFromObjects(
                objectPath.OldInstance,
                objectPath.NewInstance);

            if (IsSimpleType(pathType))
            {
                var shallowChange = GetShallowChange(
                    objectPath.BasePropertyPath,
                    objectPath.OldInstance,
                    objectPath.NewInstance);
                if (shallowChange != Change.Empty)
                {
                    result.Add(shallowChange);
                    if (objectPath.ContainerChange != Change.Empty)
                    {
                        result.Add(objectPath.ContainerChange);
                    }
                }
            }
            else if (IsEnumerableType(pathType))
            {
                Array itemsOldArray;
                Array itemsNewArray;

                if (pathType.IsArray)
                {
                    itemsOldArray = (Array)objectPath.OldInstance;
                    itemsNewArray = (Array)objectPath.NewInstance;
                }
                else
                {
                    var genericType = pathType
                                      .GetInterfaces()
                                      .Single(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                                      .GetGenericArguments()
                                      .Single();

                    var toArrayMethod = typeof(Enumerable)
                                        .GetMethods()
                                        .Single(x =>
                                                x.Name == nameof(Enumerable.ToArray) &&
                                                x.IsGenericMethod)
                                        .MakeGenericMethod(genericType);

                    var emptyMethod = typeof(Array)
                                      .GetMethods()
                                      .Single(x =>
                                              x.Name == nameof(Array.Empty) &&
                                              x.IsGenericMethod)
                                      .MakeGenericMethod(genericType);

                    itemsOldArray = objectPath.OldInstance == null
                        ? (Array)emptyMethod.Invoke(null, Array.Empty <object>())
                        : (Array)toArrayMethod.Invoke(null, new[] { objectPath.OldInstance });

                    itemsNewArray = objectPath.NewInstance == null
                        ? (Array)emptyMethod.Invoke(null, Array.Empty <object>())
                        : (Array)toArrayMethod.Invoke(null, new[] { objectPath.NewInstance });
                }

                var maxCount = Math.Max(itemsOldArray.Length, itemsNewArray.Length);

                var newItemsOldArray = new object[maxCount];
                var newItemsNewArray = new object[maxCount];

                Array.Copy(itemsOldArray, newItemsOldArray, itemsOldArray.Length);
                Array.Copy(itemsNewArray, newItemsNewArray, itemsNewArray.Length);

                var shallowChange = GetShallowChange(
                    objectPath.BasePropertyPath ?? string.Empty,
                    objectPath.OldInstance,
                    objectPath.NewInstance);

                for (var i = 0; i < maxCount; i++)
                {
                    var itemOldInstance = newItemsOldArray[i];
                    var itemNewInstance = newItemsNewArray[i];

                    var itemType = GetTypeFromObjects(itemOldInstance, itemNewInstance);
                    if (itemType == null)
                    {
                        continue;
                    }

                    var arrayItemObjectPath = new ObjectPath()
                    {
                        BasePropertyPath = AddToPropertyPath(
                            objectPath.BasePropertyPath,
                            i.ToString()),
                        OldInstance     = itemOldInstance,
                        NewInstance     = itemNewInstance,
                        Properties      = itemType.GetProperties(),
                        ContainerChange = shallowChange
                    };

                    contextPair.ObjectPathQueue.Enqueue(arrayItemObjectPath);
                }
            }
            else
            {
                EnqueueObjectPathQueues(
                    contextPair,
                    objectPath);
            }
        }
        private static void ScanForChanges(ContextPair contextPair, ObjectPath objectPath, ChangeCollection result)
        {
            var pathType = GetTypeFromObjects(
                objectPath.OldInstance,
                objectPath.NewInstance);

            if (IsSimpleType(pathType))
            {
                var shallowChange = GetShallowChange(
                    objectPath.BasePropertyPath,
                    objectPath.OldInstance,
                    objectPath.NewInstance);
                if (shallowChange == Change.Empty)
                {
                    return;
                }

                result.Add(shallowChange);
                if (objectPath.ParentChanges == null)
                {
                    return;
                }

                foreach (var parentChange in objectPath.ParentChanges)
                {
                    result.Add(parentChange);
                }
            }
            else if (IsEnumerableType(pathType))
            {
                if (pathType == null)
                {
                    throw new InvalidOperationException("Type was enumerable despite being null.");
                }

                Array?itemsOldArray;
                Array?itemsNewArray;

                if (pathType.IsArray)
                {
                    itemsOldArray = (Array?)objectPath.OldInstance;
                    itemsNewArray = (Array?)objectPath.NewInstance;
                }
                else
                {
                    var genericType = pathType
                                      .GetInterfaces()
                                      .Single(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                                      .GetGenericArguments()
                                      .Single();

                    var toArrayMethod = typeof(Enumerable)
                                        .GetMethods()
                                        .Single(x =>
                                                x.Name == nameof(Enumerable.ToArray) &&
                                                x.IsGenericMethod)
                                        .MakeGenericMethod(genericType);

                    var emptyMethod = typeof(Array)
                                      .GetMethods()
                                      .Single(x =>
                                              x.Name == nameof(Array.Empty) &&
                                              x.IsGenericMethod)
                                      .MakeGenericMethod(genericType);

                    itemsOldArray = objectPath.OldInstance == null
                        ? (Array)emptyMethod.Invoke(null, Array.Empty <object>())
                        : (Array)toArrayMethod.Invoke(null, new[] { objectPath.OldInstance });

                    itemsNewArray = objectPath.NewInstance == null
                        ? (Array)emptyMethod.Invoke(null, Array.Empty <object>())
                        : (Array)toArrayMethod.Invoke(null, new[] { objectPath.NewInstance });
                }

                var maxCount = Math.Max(
                    itemsOldArray?.Length ?? 0,
                    itemsNewArray?.Length ?? 0);

                var newItemsOldArray = new object[maxCount];
                var newItemsNewArray = new object[maxCount];

                Array.Copy(itemsOldArray ?? Array.Empty <object>(), newItemsOldArray, itemsOldArray?.Length ?? 0);
                Array.Copy(itemsNewArray ?? Array.Empty <object>(), newItemsNewArray, itemsNewArray?.Length ?? 0);

                var shallowChange = new Change(
                    objectPath.BasePropertyPath ?? string.Empty,
                    objectPath.OldInstance,
                    objectPath.NewInstance);
                var newParentChanges = new[]
                {
                    shallowChange
                };

                var parentChanges = objectPath.ParentChanges == null ?
                                    newParentChanges :
                                    objectPath
                                    .ParentChanges
                                    .Union(newParentChanges)
                                    .Distinct()
                                    .ToArray();

                for (var i = 0; i < maxCount; i++)
                {
                    var itemOldInstance = newItemsOldArray[i];
                    var itemNewInstance = newItemsNewArray[i];

                    var itemType = GetTypeFromObjects(itemOldInstance, itemNewInstance);
                    if (itemType == null)
                    {
                        continue;
                    }

                    var arrayItemObjectPath = new ObjectPath()
                    {
                        BasePropertyPath = AddToPropertyPath(
                            objectPath.BasePropertyPath,
                            i.ToString()),
                        OldInstance   = itemOldInstance,
                        NewInstance   = itemNewInstance,
                        Properties    = itemType.GetProperties(),
                        ParentChanges = parentChanges
                    };

                    contextPair.ObjectPathQueue.Enqueue(arrayItemObjectPath);
                }
            }
            else
            {
                EnqueueObjectPathQueues(
                    contextPair,
                    objectPath);
            }
        }