/// <summary>
 /// Gets an <see cref="IProperty"/> on the specified container for the given <see cref="PropertyPath"/>.
 /// </summary>
 /// <remarks>
 /// While the container data is not actually read from or written to. The container itself is needed to resolve polymorphic fields and list elements.
 /// </remarks>
 /// <param name="container">The container tree to search.</param>
 /// <param name="path">The property path to resolve.</param>
 /// <returns>The <see cref="IProperty"/> for the given path.</returns>
 /// <exception cref="ArgumentNullException">The specified container or path is null.</exception>
 /// <exception cref="InvalidContainerTypeException">The specified container type is not valid for visitation.</exception>
 /// <exception cref="MissingPropertyBagException">The specified container type has no property bag associated with it.</exception>
 /// <exception cref="InvalidPathException">The specified <paramref name="path"/> was not found or could not be resolved.</exception>
 public static IProperty GetProperty(ref object container, PropertyPath path)
 => GetProperty <object>(ref container, path);
 /// <summary>
 /// Gets an <see cref="IProperty"/> on the specified container for the given <see cref="PropertyPath"/>.
 /// </summary>
 /// <remarks>
 /// While the container data is not actually read from or written to. The container itself is needed to resolve polymorphic fields and list elements.
 /// </remarks>
 /// <param name="container">The container tree to search.</param>
 /// <param name="path">The property path to resolve.</param>
 /// <param name="property">When this method returns, contains the property associated with the specified path, if the property is found; otherwise, null.</param>
 /// <returns><see langword="true"/> if the property was found at the specified path; otherwise, <see langword="false"/>.</returns>
 public static bool TryGetProperty(ref object container, PropertyPath path, out IProperty property)
 => GetProperty(ref container, path, out property, out _);
Beispiel #3
0
        /// <summary>
        /// Visit the specified <paramref name="container"/> using the specified <paramref name="visitor"/> at the given <see cref="PropertyPath"/>.
        /// </summary>
        /// <param name="container">The container to visit.</param>
        /// <param name="visitor">The visitor.</param>
        /// <param name="path">The property path to visit.</param>
        /// <param name="parameters">The visit parameters to use.</param>
        /// <typeparam name="TContainer">The container type.</typeparam>
        /// <exception cref="ArgumentNullException">The container is null.</exception>
        /// <exception cref="InvalidContainerTypeException">The given container type is not valid for visitation.</exception>
        /// <exception cref="MissingPropertyBagException">No property bag was found for the given container.</exception>
        public static void Visit <TContainer>(ref TContainer container, PropertyVisitor visitor, PropertyPath path, VisitParameters parameters = default)
        {
            var visitAtPath = ValueAtPathVisitor.Pool.Get();

            try
            {
                visitAtPath.Path    = path;
                visitAtPath.Visitor = visitor;

                Visit(ref container, visitAtPath, parameters);

                if ((parameters.IgnoreExceptions & VisitExceptionType.Internal) != 0)
                {
                    switch (visitAtPath.ErrorCode)
                    {
                    case VisitErrorCode.Ok:
                        break;

                    case VisitErrorCode.InvalidPath:
                        throw new InvalidPathException($"Failed to Visit at Path=[{path}]");

                    default:
                        throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{visitAtPath.ErrorCode}]");
                    }
                }
            }
            finally
            {
                ValueAtPathVisitor.Pool.Release(visitAtPath);
            }
        }
 /// <summary>
 /// Gets an <see cref="IProperty"/> on the specified container for the given <see cref="PropertyPath"/>.
 /// </summary>
 /// <remarks>
 /// While the container data is not actually read from or written to. The container itself is needed to resolve polymorphic fields and list elements.
 /// </remarks>
 /// <param name="container">The container tree to search.</param>
 /// <param name="path">The property path to resolve.</param>
 /// <param name="property">When this method returns, contains the property associated with the specified path, if the property is found; otherwise, null.</param>
 /// <typeparam name="TContainer">The strongly typed container.</typeparam>
 /// <returns><see langword="true"/> if the property was found at the specified path; otherwise, <see langword="false"/>.</returns>
 public static bool TryGetProperty <TContainer>(ref TContainer container, PropertyPath path, out IProperty property)
 => GetProperty(ref container, path, out property, out _);
 /// <summary>
 /// Gets the value of a property by path.
 /// </summary>
 /// <param name="container">The container whose property value will be returned.</param>
 /// <param name="path">The path of the property to get.</param>
 /// <typeparam name="TValue">The value type.</typeparam>
 /// <returns>The value at the specified path.</returns>
 /// <exception cref="ArgumentNullException">The specified container or path is null.</exception>
 /// <exception cref="InvalidContainerTypeException">The specified container type is not valid for visitation.</exception>
 /// <exception cref="MissingPropertyBagException">The specified container type has no property bag associated with it.</exception>
 /// <exception cref="InvalidCastException">The specified <typeparamref name="TValue"/> could not be assigned to the property.</exception>
 /// <exception cref="InvalidPathException">The specified <paramref name="path"/> was not found or could not be resolved.</exception>
 public static TValue GetValue <TValue>(ref object container, PropertyPath path)
 => GetValue <object, TValue>(ref container, path);
Beispiel #6
0
 /// <summary>
 /// Returns <see langword="true"/> if a property exists at the specified <see cref="PropertyPath"/>.
 /// </summary>
 /// <param name="container">The container tree to search.</param>
 /// <param name="path">The property path to resolve.</param>
 /// <returns><see langword="true"/> if a property can be found at path.</returns>
 public static bool IsPathValid(ref object container, PropertyPath path)
 => IsPathValid <object>(ref container, path);
 public static bool TryGetValue <TContainer, TTargetValue>(ref TContainer container, PropertyPath propertyPath,
                                                           int propertyPathIndex, ref ChangeTracker changeTracker, out TTargetValue value)
 {
     return(TryGetValueImpl(ref container, propertyPath, propertyPathIndex, ref changeTracker, out value) == VisitErrorCode.Ok);
 }
 /// <summary>
 /// Gets the value of a property by path.
 /// </summary>
 /// <param name="container">The container whose property value will be returned.</param>
 /// <param name="path">The path of the property to get.</param>
 /// <param name="value">When this method returns, contains the value associated with the specified path, if the property is found. otherwise the default value for the <typeparamref name="TValue"/>.</param>
 /// <typeparam name="TContainer">The container type.</typeparam>
 /// <typeparam name="TValue">The value type.</typeparam>
 /// <returns><see langword="true"/> if the value exists at the specified path; otherwise, <see langword="false"/>.</returns>
 public static bool TryGetValue <TContainer, TValue>(ref TContainer container, PropertyPath path, out TValue value)
 => GetValue(ref container, path, out value, out _);
        static VisitErrorCode TryGetValueImpl <TContainer, TTargetValue>(ref TContainer container, PropertyPath propertyPath,
                                                                         int propertyPathIndex, ref ChangeTracker changeTracker, out TTargetValue value)
        {
            var action = new GetValueAtPathAction <TContainer, TTargetValue>(propertyPath, propertyPathIndex);

            if (PropertyBagResolver.Resolve <TContainer>()
                .FindProperty(propertyPath[propertyPathIndex].Name, ref container, ref changeTracker, ref action))
            {
                value = action.Value;
                return(action.ErrorCode);
            }

            if (typeof(TContainer) != container.GetType())
            {
                return(GetValueFromActualTypeCallback <TTargetValue> .TryExecute(container, propertyPath, propertyPathIndex, ref changeTracker, out value));
            }

            value = default;
            return(VisitErrorCode.InvalidPath);
        }
        static VisitErrorCode VisitGetValueProperty <TContainer, TProperty, TValue, TTargetValue>(TProperty property,
                                                                                                  ref TContainer container, PropertyPath propertyPath, int propertyPathIndex, ref ChangeTracker changeTracker, out TTargetValue value)
            where TProperty : IProperty <TContainer, TValue>
        {
            if (propertyPathIndex < propertyPath.PartsCount - 1)
            {
                var sub = property.GetValue(ref container);
                return(TryGetValueImpl(ref sub, propertyPath, propertyPathIndex + 1, ref changeTracker, out value));
            }

            if (TypeConversion.TryConvert(property.GetValue(ref container), out value))
            {
                return(VisitErrorCode.Ok);
            }

            return(VisitErrorCode.InvalidCast);
        }
        public static TTargetValue GetValue <TContainer, TTargetValue>(ref TContainer container, PropertyPath propertyPath,
                                                                       int propertyPathIndex, ref ChangeTracker changeTracker)
        {
            var status = TryGetValueImpl(ref container, propertyPath, propertyPathIndex, ref changeTracker, out TTargetValue value);

            switch (status)
            {
            case VisitErrorCode.InvalidPath:
                throw new ArgumentException($"Cannot get collection count at `{propertyPath}`");

            case VisitErrorCode.InvalidCast:
                throw new InvalidCastException($"Could not get value of type {typeof(TTargetValue).Name} at `{propertyPath}`");
            }

            return(value);
        }
Beispiel #12
0
        public static void SetValue <TContainer, TTargetValue>(ref TContainer container, PropertyPath propertyPath,
                                                               int propertyPathIndex, TTargetValue value, ref ChangeTracker changeTracker)
        {
            var status = TrySetValueImpl(ref container, propertyPath, propertyPathIndex, value, ref changeTracker);

            switch (status)
            {
            case VisitErrorCode.InvalidPath: throw new ArgumentException($"Could not set value at `{propertyPath}`");

            case VisitErrorCode.InvalidCast: throw new InvalidCastException($"Could not set value of type {typeof(TTargetValue).Name} at `{propertyPath}`");
            }
        }
Beispiel #13
0
        static VisitErrorCode VisitCollectionSetCountProperty <TContainer, TProperty, TPropertyValue>(TProperty property,
                                                                                                      ref TContainer container, PropertyPath propertyPath, int propertyPathIndex, int count, ref ChangeTracker changeTracker)
            where TProperty : ICollectionProperty <TContainer, TPropertyValue>
        {
            if (propertyPathIndex < propertyPath.PartsCount - 1)
            {
                var getter = new SetCollectionCountGetter <TContainer>(propertyPath, propertyPathIndex, count);
                property.GetPropertyAtIndex(ref container, propertyPath[propertyPathIndex].Index, ref changeTracker, ref getter);
                return(getter.ErrorCode);
            }

            var value = property.GetValue(ref container);

            property.SetCount(ref container, count);
            property.SetValue(ref container, value);
            return(VisitErrorCode.Ok);
        }
Beispiel #14
0
 public static bool TrySetCount <TContainer>(ref TContainer container, PropertyPath propertyPath, int propertyPathIndex,
                                             int count, ref ChangeTracker changeTracker)
 {
     return(TrySetCountImpl(ref container, propertyPath, propertyPathIndex, count, ref changeTracker) == VisitErrorCode.Ok);
 }
Beispiel #15
0
        static VisitErrorCode VisitSetCountProperty <TContainer, TProperty, TPropertyValue>(TProperty property,
                                                                                            ref TContainer container, PropertyPath propertyPath, int propertyPathIndex, int count, ref ChangeTracker changeTracker)
            where TProperty : IProperty <TContainer, TPropertyValue>
        {
            if (propertyPathIndex < propertyPath.PartsCount - 1)
            {
                var value  = property.GetValue(ref container);
                var status = TrySetCountImpl(ref value, propertyPath, propertyPathIndex + 1, count, ref changeTracker);
                if (status == VisitErrorCode.Ok)
                {
                    property.SetValue(ref container, value);
                }

                return(status);
            }

            return(VisitErrorCode.InvalidPath);
        }