public static VisitResult Construct <TDstContainer, TSrcContainer>(ref TDstContainer dstContainer, ref TSrcContainer srcContainer, PropertyContainerConstructOptions options = default)
        {
            if (!RuntimeTypeInfoCache <TSrcContainer> .IsValueType() && srcContainer == null)
            {
                throw new ArgumentNullException(nameof(srcContainer));
            }

            if (!RuntimeTypeInfoCache <TDstContainer> .IsValueType() && dstContainer == null)
            {
                if (typeof(UnityEngine.Object).IsAssignableFrom(typeof(TDstContainer)))
                {
                    throw new ArgumentNullException(nameof(dstContainer));
                }

                if (!TypeConstruction.TryConstruct(srcContainer.GetType(), out dstContainer))
                {
                    throw new ArgumentNullException(nameof(dstContainer));
                }
            }

            var result = VisitResult.GetPooled();

            Construct(ref dstContainer, ref srcContainer, result, options);
            return(result);
        }
            public void VisitCollectionProperty <TDstProperty, TDstValue>(
                TDstProperty dstProperty,
                ref TDstContainer dstContainer,
                ref ChangeTracker changeTracker)
                where TDstProperty : ICollectionProperty <TDstContainer, TDstValue>
            {
                if (!RuntimeTypeInfoCache <TSrcValue> .IsValueType() && null == SrcValue)
                {
                    dstProperty.SetValue(ref dstContainer, default);
                    return;
                }

                var dstValue = dstProperty.GetValue(ref dstContainer);

                if (!RuntimeTypeInfoCache <TDstValue> .IsValueType() && null == dstValue)
                {
                    if (typeof(UnityEngine.Object).IsAssignableFrom(typeof(TDstValue)))
                    {
                        return;
                    }

                    if (TypeConstruction.TryConstruct(SrcValue.GetType(), out dstValue))
                    {
                        dstProperty.SetValue(ref dstContainer, dstValue);
                    }
                    else if (TypeConstruction.TryConstruct(out dstValue))
                    {
                        dstProperty.SetValue(ref dstContainer, dstValue);
                    }
                    else if (typeof(TDstValue).IsArray)
                    {
                        dstValue = (TDstValue)Activator.CreateInstance(typeof(TDstValue), SrcProperty.GetCount(ref SrcContainer));
                        dstProperty.SetValue(ref dstContainer, dstValue);
                    }
                }

                var srcCount = SrcProperty.GetCount(ref SrcContainer);
                var dstCount = dstProperty.GetCount(ref dstContainer);

                if (srcCount != dstCount)
                {
                    dstProperty.SetCount(ref dstContainer, srcCount);
                }

                for (var i = 0; i < srcCount; i++)
                {
                    var action = new SrcCollectionElementGetter <TDstProperty, TDstValue>
                    {
                        Options      = Options,
                        Result       = Result,
                        DstProperty  = dstProperty,
                        DstContainer = dstContainer,
                        Index        = i
                    };

                    SrcProperty.GetPropertyAtIndex(ref SrcContainer, i, ref changeTracker, ref action);

                    dstContainer = action.DstContainer;
                }
            }
        public static bool TryConstructFromData <TDstValue, TSrcValue>(ref TSrcValue srcValue, string typeIdentifierKey, VisitResult result, out TDstValue dstValue)
        {
            if (typeof(UnityEngine.Object).IsAssignableFrom(typeof(TDstValue)))
            {
                dstValue = default;
                return(false);
            }

            // Try to construct based on the source type.
            if (TypeConstruction.TryConstruct(srcValue.GetType(), out dstValue))
            {
                return(true);
            }

            // Try to construct based on the destination type.
            if (TypeConstruction.TryConstruct(out dstValue))
            {
                return(true);
            }

            // If type identifier key option is not set, cannot construct this type.
            if (string.IsNullOrEmpty(typeIdentifierKey))
            {
                return(false);
            }

            // Try to get destination type name from type identifier meta data.
            if (!PropertyContainer.TryGetValue(ref srcValue, typeIdentifierKey, out string assemblyQualifiedTypeName))
            {
                result.AddLog($"PropertyContainer.Construct failed to construct DstType=[{typeof(TDstValue)}]. SrcValue Property=[{typeIdentifierKey}] was not found.");
                return(false);
            }

            // Verify destination type name is valid.
            if (string.IsNullOrEmpty(assemblyQualifiedTypeName))
            {
                result.AddException(new InvalidOperationException($"PropertyContainer.Construct failed to construct DstType=[{typeof(TDstValue)}]. SrcValue Property=[{typeIdentifierKey}] contained null or empty type information."));
                return(false);
            }

            // Try to get destination type.
            var dstType = Type.GetType(assemblyQualifiedTypeName);

            if (null == dstType)
            {
                result.AddException(new InvalidOperationException($"PropertyContainer.Construct failed to construct DstType=[{typeof(TDstValue)}]. Could not resolve type from TypeName=[{assemblyQualifiedTypeName}]."));
                return(false);
            }

            return(TypeConstruction.TryConstruct(dstType, out dstValue));
        }