/// <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 _);
/// <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);
/// <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); }
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}`"); } }
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); }
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); }
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); }