示例#1
0
        /// <inheritdoc/>
        public void Refresh(object newObjectValue)
        {
            if (!(newObjectValue is IEnumerable))
            {
                throw new ArgumentException(@"The object is not an IEnumerable", nameof(newObjectValue));
            }

            ObjectValue = newObjectValue;

            references.Clear();
            references.AddRange(
                IsDictionary
                    ? ((IEnumerable)ObjectValue).Cast <object>().Select(x => (ObjectReference)Reference.CreateReference(GetValue(x), elementType, GetKey(x)))
                    : ((IEnumerable)ObjectValue).Cast <object>().Select((x, i) => (ObjectReference)Reference.CreateReference(x, elementType, new Index(i))));
            indices.Clear();
            foreach (var reference in references)
            {
                indices.Add(reference.Index);
            }
        }
示例#2
0
        public void Refresh(IGraphNode ownerNode, NodeContainer nodeContainer, NodeFactoryDelegate nodeFactory)
        {
            var newObjectValue = ownerNode.Content.Value;

            if (!(newObjectValue is IEnumerable))
            {
                throw new ArgumentException(@"The object is not an IEnumerable", nameof(newObjectValue));
            }

            ObjectValue = newObjectValue;

            var newReferences = new HybridDictionary <Index, ObjectReference>();

            if (IsDictionary)
            {
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = GetKey(item);
                    var value = (ObjectReference)Reference.CreateReference(GetValue(item), elementType, key);
                    newReferences.Add(key, value);
                }
            }
            else
            {
                var i = 0;
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = new Index(i);
                    var value = (ObjectReference)Reference.CreateReference(item, elementType, key);
                    newReferences.Add(key, value);
                    ++i;
                }
            }

            // The reference need to be updated if it has never been initialized, if the number of items is different, or if any index or any value is different.
            var needUpdate = items == null || newReferences.Count != items.Count || !AreItemsEqual(items, newReferences);

            if (needUpdate)
            {
                // We create a mapping values of the old list of references to their corresponding target node. We use a list because we can have multiple times the same target in items.
                var oldReferenceMapping = new List <KeyValuePair <object, ObjectReference> >();
                if (items != null)
                {
                    oldReferenceMapping.AddRange(items.Values.Where(x => x.ObjectValue != null && !(x.TargetNode?.Content is BoxedContent)).Select(x => new KeyValuePair <object, ObjectReference>(x.ObjectValue, x)));
                }

                foreach (var newReference in newReferences)
                {
                    if (newReference.Value.ObjectValue != null)
                    {
                        var found = false;
                        var i     = 0;
                        foreach (var item in oldReferenceMapping)
                        {
                            if (Equals(newReference.Value.ObjectValue, item.Key))
                            {
                                // If this value was already present in the old list of reference, just use the same target node in the new list.
                                newReference.Value.SetTarget(item.Value.TargetNode);
                                // Remove consumed existing reference so if there is a second entry with the same "key", it will be the other reference that will be used.
                                oldReferenceMapping.RemoveAt(i);
                                found = true;
                                break;
                            }
                            ++i;
                        }
                        if (!found)
                        {
                            // Otherwise, do a full update that will properly initialize the new reference.
                            newReference.Value.Refresh(ownerNode, nodeContainer, nodeFactory, newReference.Key);
                        }
                    }
                }
                items = newReferences;
                // Remark: this works because both KeyCollection and List implements IReadOnlyCollection. Any internal change to HybridDictionary might break this!
                Indices = (IReadOnlyCollection <Index>)newReferences.Keys;
            }
        }
示例#3
0
        public void Refresh(IContentNode ownerNode, NodeContainer nodeContainer)
        {
            var newObjectValue = ownerNode.Value;

            if (!(newObjectValue is IEnumerable))
            {
                throw new ArgumentException(@"The object is not an IEnumerable", nameof(newObjectValue));
            }

            ObjectValue = newObjectValue;

            var newReferences = new HybridDictionary <Index, ObjectReference>();

            if (IsDictionary)
            {
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = GetKey(item);
                    var value = (ObjectReference)Reference.CreateReference(GetValue(item), ElementType, key);
                    newReferences.Add(key, value);
                }
            }
            else
            {
                var i = 0;
                foreach (var item in (IEnumerable)ObjectValue)
                {
                    var key   = new Index(i);
                    var value = (ObjectReference)Reference.CreateReference(item, ElementType, key);
                    newReferences.Add(key, value);
                    ++i;
                }
            }

            // The reference need to be updated if it has never been initialized, if the number of items is different, or if any index or any value is different.
            var needUpdate = items == null || newReferences.Count != items.Count || !AreItemsEqual(items, newReferences);

            if (needUpdate)
            {
                // We create a mapping values of the old list of references to their corresponding target node. We use a list because we can have multiple times the same target in items.
                var oldReferenceMapping = new List <KeyValuePair <object, ObjectReference> >();
                if (items != null)
                {
                    var existingIndices = ContentNode.GetIndices(ownerNode).ToList();
                    foreach (var item in items)
                    {
                        var boxedTarget = item.Value.TargetNode as BoxedContent;
                        // For collection of struct, we need to update the target nodes first so equity comparer will work. Careful tho, we need to skip removed items!
                        if (boxedTarget != null && existingIndices.Contains(item.Key))
                        {
                            // If we are boxing a struct, we reuse the same nodes if they are type-compatible and just overwrite the struct value.
                            var value = ownerNode.Retrieve(item.Key);
                            if (value?.GetType() == item.Value.TargetNode?.Type)
                            {
                                boxedTarget.UpdateFromOwner(ownerNode.Retrieve(item.Key));
                            }
                        }
                        if (item.Value.ObjectValue != null)
                        {
                            oldReferenceMapping.Add(new KeyValuePair <object, ObjectReference>(item.Value.ObjectValue, item.Value));
                        }
                    }
                }

                foreach (var newReference in newReferences)
                {
                    if (newReference.Value.ObjectValue != null)
                    {
                        var found = false;
                        var i     = 0;
                        foreach (var item in oldReferenceMapping)
                        {
                            if (Equals(newReference.Value.ObjectValue, item.Key))
                            {
                                // If this value was already present in the old list of reference, just use the same target node in the new list.
                                newReference.Value.SetTarget(item.Value.TargetNode);
                                // Remove consumed existing reference so if there is a second entry with the same "key", it will be the other reference that will be used.
                                oldReferenceMapping.RemoveAt(i);
                                found = true;
                                break;
                            }
                            ++i;
                        }
                        if (!found)
                        {
                            // Otherwise, do a full update that will properly initialize the new reference.
                            newReference.Value.Refresh(ownerNode, nodeContainer, newReference.Key);
                        }
                    }
                }
                items = newReferences;
                // Remark: this works because both KeyCollection and List implements IReadOnlyCollection. Any internal change to HybridDictionary might break this!
                Indices = (IReadOnlyCollection <Index>)newReferences.Keys;
            }
        }
示例#4
0
        public void Refresh(IGraphNode ownerNode, NodeContainer nodeContainer, NodeFactoryDelegate nodeFactory)
        {
            var newObjectValue = ownerNode.Content.Value;

            if (!(newObjectValue is IEnumerable))
            {
                throw new ArgumentException(@"The object is not an IEnumerable", nameof(newObjectValue));
            }

            ObjectValue = newObjectValue;

            // First, let's build a new list of uninitialized references
            var newReferences = new List <ObjectReference>(IsDictionary
                ? ((IEnumerable)ObjectValue).Cast <object>().Select(x => (ObjectReference)Reference.CreateReference(GetValue(x), elementType, GetKey(x)))
                : ((IEnumerable)ObjectValue).Cast <object>().Select((x, i) => (ObjectReference)Reference.CreateReference(x, elementType, new Index(i))));

            // The reference need to be updated if it has never been initialized, if the number of items is different, or if any index or any value is different.
            var needUpdate = references == null || newReferences.Count != references.Count || newReferences.Zip(references).Any(x => !x.Item1.Index.Equals(x.Item2.Index) || !Equals(x.Item1.ObjectValue, x.Item2.ObjectValue));

            if (needUpdate)
            {
                // We create a dictionary that maps values of the old list of references to their corresponding target node.
                var dictionary = references?.Where(x => x.ObjectValue != null && !(x.TargetNode?.Content is BoxedContent)).ToDictionary(x => x.ObjectValue) ?? new Dictionary <object, ObjectReference>();
                foreach (var newReference in newReferences)
                {
                    if (newReference.ObjectValue != null)
                    {
                        ObjectReference oldReference;
                        if (dictionary.TryGetValue(newReference.ObjectValue, out oldReference))
                        {
                            // If this value was already present in the old list of reference, just use the same target node in the new list.
                            newReference.SetTarget(oldReference.TargetNode);
                        }
                        else
                        {
                            // Otherwise, do a full update that will properly initialize the new reference.
                            newReference.Refresh(ownerNode, nodeContainer, nodeFactory, newReference.Index);
                        }
                    }
                }
                references = newReferences;
                indices    = newReferences.Select(x => x.Index).ToList();
            }
        }