/// <summary> /// Tries to visit the specified <paramref name="container"/> by ref using the specified <paramref name="visitor"/>. /// </summary> /// <param name="visitor">The visitor.</param> /// <param name="container">The container to visit.</param> /// <param name="errorCode">When this method returns, contains the error code.</param> /// <typeparam name="TContainer">The declared container type.</typeparam> /// <returns><see langword="true"/> if the visitation succeeded; <see langword="false"/> otherwise.</returns> public static bool TryAccept <TContainer>(IPropertyBagVisitor visitor, ref TContainer container, out VisitErrorCode errorCode) { if (!RuntimeTypeInfoCache <TContainer> .IsContainerType) { errorCode = VisitErrorCode.InvalidContainerType; return(false); } // Can not visit a null container. if (RuntimeTypeInfoCache <TContainer> .CanBeNull) { if (EqualityComparer <TContainer> .Default.Equals(container, default)) { errorCode = VisitErrorCode.NullContainer; return(false); } } if (!RuntimeTypeInfoCache <TContainer> .IsValueType && typeof(TContainer) != container.GetType()) { if (!RuntimeTypeInfoCache.IsContainerType(container.GetType())) { errorCode = VisitErrorCode.InvalidContainerType; return(false); } var properties = PropertyBagStore.GetPropertyBag(container.GetType()); if (null == properties) { errorCode = VisitErrorCode.MissingPropertyBag; return(false); } // At this point the generic parameter is useless to us since it's not the correct type. // Instead we need to retrieve the untyped property bag and accept on that. Since we don't know the type // We need to box the container and let the property bag cast it internally. var boxed = (object)container; properties.Accept(visitor, ref boxed); container = (TContainer)boxed; } else { var properties = PropertyBagStore.GetPropertyBag <TContainer>(); if (null == properties) { errorCode = VisitErrorCode.MissingPropertyBag; return(false); } PropertyBag.AcceptWithSpecializedVisitor(properties, visitor, ref container); } errorCode = VisitErrorCode.Ok; return(true); }
/// <summary> /// Visit the specified <paramref name="container"/> using the specified <paramref name="visitor"/>. /// </summary> /// <param name="visitor">The visitor.</param> /// <param name="container">The container to visit.</param> /// <param name="parameters">The visit parameters to use.</param> /// <typeparam name="TContainer">The declared container type.</typeparam> /// <exception cref="ArgumentNullException">The container is null.</exception> /// <exception cref="InvalidContainerTypeException">The container is null.</exception> /// <exception cref="MissingPropertyBagException">No property bag was found for the given container.</exception> public static void Accept <TContainer>(IPropertyBagVisitor visitor, ref TContainer container, VisitParameters parameters = default) { var errorCode = VisitErrorCode.Ok; try { if (TryAccept(visitor, ref container, out errorCode)) { return; } } catch (Exception) { if ((parameters.IgnoreExceptions & VisitExceptionType.Visitor) == 0) { throw; } } if ((parameters.IgnoreExceptions & VisitExceptionType.Internal) != 0) { return; } switch (errorCode) { case VisitErrorCode.Ok: case VisitErrorCode.InvalidContainerType: break; case VisitErrorCode.NullContainer: throw new ArgumentException("The given container was null. Visitation only works for valid non-null containers."); case VisitErrorCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); default: throw new Exception($"Unexpected VisitErrorCode=[{errorCode}]"); } }
/// <summary> /// Visit the specified <paramref name="container"/> using the specified <paramref name="visitor"/>. /// </summary> /// <param name="visitor">The visitor.</param> /// <param name="container">The container to visit.</param> /// <param name="parameters">The visit parameters to use.</param> /// <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 Accept <TContainer>(IPropertyBagVisitor visitor, TContainer container, VisitParameters parameters = default) { Accept(visitor, ref container, parameters); }
/// <summary> /// Tries to visit the specified <paramref name="container"/> by ref using the specified <paramref name="visitor"/>. /// </summary> /// <param name="visitor">The visitor.</param> /// <param name="container">The container to visit.</param> /// <typeparam name="TContainer">The declared container type.</typeparam> /// <returns><see langword="true"/> if the visitation succeeded; <see langword="false"/> otherwise.</returns> public static bool TryAccept <TContainer>(IPropertyBagVisitor visitor, ref TContainer container) { return(TryAccept(visitor, ref container, out _)); }
internal static void AcceptWithSpecializedVisitor <TContainer>(IPropertyBag <TContainer> properties, IPropertyBagVisitor visitor, ref TContainer container) { switch (properties) { case IDictionaryPropertyBagAccept <TContainer> accept when visitor is IDictionaryPropertyBagVisitor typedVisitor: accept.Accept(typedVisitor, ref container); break; case IListPropertyBagAccept <TContainer> accept when visitor is IListPropertyBagVisitor typedVisitor: accept.Accept(typedVisitor, ref container); break; case ISetPropertyBagAccept <TContainer> accept when visitor is ISetPropertyBagVisitor typedVisitor: accept.Accept(typedVisitor, ref container); break; case ICollectionPropertyBagAccept <TContainer> accept when visitor is ICollectionPropertyBagVisitor typedVisitor: accept.Accept(typedVisitor, ref container); break; case IPropertyBagAccept <TContainer> accept when visitor is IPropertyBagVisitor typedVisitor: accept.Accept(typedVisitor, ref container); break; default: throw new ArgumentException($"{visitor.GetType()} does not implement any IPropertyBagAccept<T> interfaces."); } }