예제 #1
0
        /// <summary>
        /// Reorders the properties.
        /// </summary>
        /// <returns>The properties, in their new order.</returns>
        /// <exception cref="InvalidOperationException">Thrown if a cyclic move dependency is detected.</exception>
        public IEnumerable <PropertyInfo> ReorderProperties()
        {
            var originalProperties = new List <PropertyInfo>(OriginalProperties);

            // Check if any property exists in the precedence chain of any of its precedents
            if (MovingProperties.Any(p => HasCyclicMoveDependency(p.Key)))
            {
                throw new InvalidOperationException(
                          "A cyclical dependency was detected in the field move set. Verify that no fields are requesting invalid moves.");
            }

            // First, we'll order the original properties by declaration and inheritance
            var orderedProperties = originalProperties
                                    .OrderBy(p => p.DeclaringType, new InheritanceChainComparer())
                                    .ThenBy(p => p.MetadataToken)
                                    .ToList();

            // Then, we'll move the fields which need special handling. Order them by the length of their dependency
            // chains such that we are working our way down the chains.

            var movingPropertiesByDepth = PrecedenceChains.OrderBy(kvp => kvp.Value.Count);

            foreach (var propertyPair in movingPropertiesByDepth)
            {
                var property = propertyPair.Key;
                var propertyThatComesBeforeName = MovingProperties[property].ComesAfter;
                var propertyBefore = orderedProperties.First(p => p.Name == propertyThatComesBeforeName);

                // Find the original property in the list and remove it
                orderedProperties.Remove(property);

                // Then, find the preceding property
                int precedingPropertyIndex = orderedProperties.IndexOf(propertyBefore);

                // Finally, insert the original property after that one
                orderedProperties.Insert(precedingPropertyIndex + 1, property);
            }

            return(orderedProperties);
        }
예제 #2
0
        /// <summary>
        /// Gets the chain of preceding properties for the given property.
        /// </summary>
        /// <param name="order">The order attribute.</param>
        /// <param name="yieldedProperties">The properties that have already been yielded. Used to break out if a cyclical dependency
        /// is encountered. This list should always be empty at the first non-recursive call.
        /// </param>
        /// <returns>The chain of preceding properties that will move, terminating with the first one that will not.</returns>
        public IEnumerable <PropertyInfo> GetPrecendenceChain
        (
            RecordFieldOrderAttribute order,
            List <PropertyInfo> yieldedProperties
        )
        {
            var precedingProperty = OriginalProperties.First(p => p.Name == order.ComesAfter);

            bool willPropertyMove = MovingProperties.ContainsKey(precedingProperty);

            if (willPropertyMove && !yieldedProperties.Contains(precedingProperty))
            {
                yieldedProperties.Add(precedingProperty);
                foreach (var value in GetPrecendenceChain(MovingProperties[precedingProperty], yieldedProperties))
                {
                    yieldedProperties.Add(value);
                    yield return(value);
                }
            }

            yield return(precedingProperty);
        }