1

So i have some code that recursively creates directories and downloads the files in the folder repectively.

Here is the code:

public class Program
    {
        static void UploadDownloadProgress(Object sender, FileDataTransferEventArgs e)
        { 
            // print a dot
            Console.WriteLine("Downloading");
            Console.WriteLine(".");
            // it's ok to go forward
            e.Cancel = false;
        } 

        public static void DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, string targetDir, string sourceDir)
        {           

            foreach (ICloudFileSystemEntry fsentry in remoteDir)
            {
                var filepath = Path.Combine(targetDir, fsentry.Name);

                if (fsentry is ICloudDirectoryEntry)
                {
                    Console.WriteLine("Created: {0}", filepath);
                    Directory.CreateDirectory(filepath);
                    DownloadFolder(dropBoxStorage, fsentry as ICloudDirectoryEntry, filepath, sourceDir);
                }
                else
                {
                    dropBoxStorage.DownloadFile(remoteDir, fsentry.Name, targetDir, UploadDownloadProgress);
                }
            }
        }

        static void Main(string[] args)
        {
            CloudStorage dropBoxStorage = new CloudStorage();

            var dropBixConfig = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.DropBox);

            ICloudStorageAccessToken accessToken = null;

            using (FileStream fs = File.Open(@"C:\Users\Michael\token.txt", FileMode.Open, FileAccess.Read, FileShare.None))
            {
                accessToken = dropBoxStorage.DeserializeSecurityToken(fs);
            }

            var storageToken = dropBoxStorage.Open(dropBixConfig, accessToken);

            //do stuff
            //var root = dropBoxStorage.GetRoot();

            var publicFolder = dropBoxStorage.GetFolder("/Public");

            foreach (var folder in publicFolder)
            {
                Boolean bIsDirectory = folder is ICloudDirectoryEntry;

                Console.WriteLine("{0}: {1}", bIsDirectory ? "DIR" : "FIL", folder.Name);
            }

            string remoteDirName = @"/Public/IQSWS";
            string targetDir = @"C:\Users\Michael\";
            var remoteDir = dropBoxStorage.GetFolder(remoteDirName);

            DownloadFolder(dropBoxStorage, remoteDir, targetDir, remoteDirName);

            dropBoxStorage.Close();
        }

        public delegate void FileOperationProgressChanged(object sender, FileDataTransferEventArgs e);    
    }

After the loop finds the first file in the else, it downloads it and then moves on to the next file, however it throws an exception on the foreach:

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Collection was modified; enumeration operation may not execute.
  Source=mscorlib
  StackTrace:
       at System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator.MoveNext()
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 29
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.Main(String[] args) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 80
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

Why is this happening? Why is the array edited when all I do is download a file?

4

2 に答える 2

1

remoteDirコレクション全体を DownloadFile メソッドに渡します。これは次のようになります。

// AppLimit.CloudComputing.SharpBox.CloudStorage
public void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath, FileOperationProgressChanged delProgress)
{
    if (parent == null || name == null || targetPath == null)
    {
        throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters);
    }
    targetPath = Environment.ExpandEnvironmentVariables(targetPath);
    ICloudFileSystemEntry child = parent.GetChild(name);
    using (FileStream fileStream = new FileStream(Path.Combine(targetPath, name), FileMode.Create, FileAccess.Write, FileShare.None))
    {
        child.GetDataTransferAccessor().Transfer(fileStream, nTransferDirection.nDownload, delProgress, null);
    }
}

parentこのメソッドで変更できる唯一のポイントは、それが呼び出す場所のようGetChildです。GetChild を見る (IlSpy を使用):

public ICloudFileSystemEntry GetChild(string name)
{
  return this.GetChild(name, true);
}

public ICloudFileSystemEntry GetChild(string name, bool bThrowException)
{
  this.RefreshResource();
  ICloudFileSystemEntry cloudFileSystemEntry;
  this._subDirectories.TryGetValue(name, out cloudFileSystemEntry);
  if (cloudFileSystemEntry == null && bThrowException)
  {
    throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound);
  }
  return cloudFileSystemEntry;
}

これにより、コレクションが呼び出さRefreshResourceれます。これは次のようになります (ドロップボックスの実装を想定しています):

// AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects.BaseDirectoryEntry
private void RefreshResource()
{
    this._service.RefreshResource(this._session, this);
    this._subDirectoriesRefreshedInitially = true;
}


// AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic.DropBoxStorageProviderService
public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource)
{
    string resourceUrlInternal = this.GetResourceUrlInternal(session, resource);
    int num;
    string text = DropBoxRequestParser.RequestResourceByUrl(resourceUrlInternal, this, session, out num);
    if (text.Length == 0)
    {
        throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotRetrieveDirectoryList);
    }
    DropBoxRequestParser.UpdateObjectFromJsonString(text, resource as BaseFileEntry, this, session);
}

さて、これが呼び出されますUpdateObjectFromJsonString(巨大なのでここには貼り付けません)がresource、コレクションに属するオブジェクトを更新するようです。したがって、コレクションが変更されます...そして例外です。

正確に何が起こっているかに興味がある場合は、ソースを SharpBox にダウンロードするか、IlSpy を使用してバイナリを逆アセンブルすることをお勧めします。しかし要するに、この方法でファイルをダウンロードすると、コレクションが変更されます。

DownloadFileコレクション全体で渡されない他のオーバーロードのいずれかを使用する可能性があります。

于 2013-10-08T14:19:48.800 に答える