/// <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 _));
 }
Exemplo n.º 5
0
        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.");
            }
        }