public async Task <Stream> OpenStreamAsync(string path, FileMode mode, FileAccess access)
        {
            if (access.HasFlag(FileAccess.Write))
            {
                return(await ReadWriteRootFolder.OpenStreamForWriteAsync(path, ToCreationCollisionOption(mode)));
            }
            else
            {
                if (mode != FileMode.Open)
                {
                    throw new ArgumentException("File mode has to be FileMode.Open when FileAccess.Read is specified.");
                }

                if (await ExistsAsync(ReadWriteRootFolder, path))
                {
                    return(await ReadWriteRootFolder.OpenStreamForReadAsync(path));
                }

                if (RootFolder != ReadWriteRootFolder && await ExistsAsync(RootFolder, path))
                {
                    return(await RootFolder.OpenStreamForReadAsync(path));
                }

                throw new FileNotFoundException();
            }
        }
        internal async Task <object> DeserializeAsync(string path, Type type, Reference?parentReference, Reference?referenceToReload)
        {
            Reference reference;

            // Check if reference exists and immediately return.

            if (referenceToReload is null)
            {
                Reference?foundReference = await FindDeserializedReferenceAsync(path, type);

                if (foundReference != null)
                {
                    if (parentReference is null || parentReference.References.Add(foundReference))
                    {
                        IncrementReference(foundReference, parentReference is null);
                    }

                    return(foundReference.Object);
                }
            }

            // Reference not found, so deserialize asset.

            if (!await ExistsAsync(path))
            {
                throw new FileNotFoundException();
            }

            using Stream stream = await RootFolder.OpenStreamForReadAsync(path + FileExtension);

            Type rootObjectType = GetRootObjectType(stream);

            object rootObjectInstance = referenceToReload != null && referenceToReload.Object.GetType().IsAssignableFrom(rootObjectType)
                ? referenceToReload.Object : Activator.CreateInstance(rootObjectType);

            object result = rootObjectInstance;

            if (!type.IsInstanceOfType(rootObjectInstance) || (type == typeof(object) && rootObjectInstance is Asset))
            {
                if (!(rootObjectInstance is Asset))
                {
                    throw new InvalidOperationException();
                }

                AssetContentTypeAttribute?contentType = rootObjectInstance.GetType().GetCustomAttribute <AssetContentTypeAttribute>();

                if (type == typeof(object) && contentType != null)
                {
                    type = contentType.ContentType;
                }

                result = Activator.CreateInstance(type);
            }

            reference = referenceToReload ?? new Reference(path, result, parentReference is null);

            reference.DeserializationTask = Task.Run(async() => await DeserializeAsync(stream, rootObjectInstance, reference));

            if (referenceToReload is null)
            {
                AddReference(reference);
            }

            parentReference?.References.Add(reference);

            await reference.DeserializationTask;

            return(reference.Object);
        }