3

I always thought that by declaring var before the using will allow it to be assigned inside using and then I could still read variable outside of it. Turns out I can't :-)

ReadOnlyCollection<string> collection;
using (var archive = new SevenZipArchive(varRarFileName)) {
    collection = archive.Volumes;
    MessageBox.Show(collection.Count.ToString());  // Output 10
}
MessageBox.Show(collection.Count.ToString()); // output 0

Any way to make it work without stopping to use using

Full testing method:

private ReadOnlyCollection<string> ExtractRar(string varRarFileName, string varDestinationDirectory) {
    ReadOnlyCollection<string> collection;
    using (var archive = new SevenZipArchive(varRarFileName)) {
        collection = new ReadOnlyCollection<string>(archive.Volumes); 
        MessageBox.Show(collection.Count.ToString()); // output 10
    }
    MessageBox.Show(collection.Count.ToString()); // output 0
    return collection;
}
0

5 Answers 5

7

As Joel Rondeau points out in his answer, the collection is being cleared as the archive is being disposed of. However, wrapping it in a ReadonlyCollection won't work as this does not copy the wrapped list. You need to create this copy manually:

ReadOnlyCollection<string> collection;
using (var archive = new SevenZipArchive(varRarFileName))
{
    collection = new ReadOnlyCollection<string>(archive.Volumes.ToList());
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes. Checked documentation and my new theory certainly won't work in this case. This is much better.
6

Copy archive.Volumes instead of just having collection reference it. Then when archive is disposed at the end of the using, your collection won't have been disposed.

1 Comment

I changed it to that and it still goes 0 when outside of using.. I've added example of what i use to my post.
2

You can definitely still read from the variable. There's no problem in terms of definite assignment, or you'd get a compile-time error. For example, this is fine:

using System;
using System.IO;

class Test
{
    static void Main()
    {
        string x;
        using (new MemoryStream())
        {
            x = "hello";
        }
        Console.WriteLine(x);
    }
}

That's absolutely fine.

Now if SevenZipArchive returns a ReadOnlyCollection<string>, I'd usually expect that to still be valid after the archive itself is disposed. However, ReadOnlyCollection<T> is simply a wrapper around another collection... and if that collection is being invalidated by disposing of archive, that would certainly explain things.

Unfortunately, Joel's suggested way of copying the collection is only creating another wrapper - which will ask the first wrapper for the count, in turn asking the original (invalidated) collection.

Here's one approach which should work:

private ReadOnlyCollection<string> ExtractRar(string varRarFileName,
                                              string varDestinationDirectory) {
    ReadOnlyCollection<string> collection;
    using (var archive = new SevenZipArchive(varRarFileName)) {
        collection = new ReadOnlyCollection<string>(archive.Volumes.ToList()); 
        MessageBox.Show(collection.Count.ToString()); // output 10
    }
    MessageBox.Show(collection.Count.ToString()); // output 0
    return collection;
}

Note the extra call to ToList(). That will force the collection to be copied to a List<string> first... truly copied, not just creating a wrapper.

Of course, if you don't really mind if the method returns a List, you could just use:

private List<string> ExtractRar(string varRarFileName,
                                string varDestinationDirectory) {
    List<string> collection;
    using (var archive = new SevenZipArchive(varRarFileName)) {
        collection = archive.Volumes.ToList(); 
        MessageBox.Show(collection.Count.ToString()); // output 10
    }
    MessageBox.Show(collection.Count.ToString()); // output 0
    return collection;
}

... and then when you don't need the extra diagnostics:

private List<string> ExtractRar(string varRarFileName,
                                string varDestinationDirectory) {
    using (var archive = new SevenZipArchive(varRarFileName)) {
        return archive.Volumes.ToList(); 
    }
}

(I'm assuming you're using .NET 3.5 or higher, by the way, to use the ToList extension method.)

4 Comments

Well then why do i get count = 10 when inside the using, and when outside it goes 0?
How can I prevent it to be disposed except to not use disposing?
Yes, my fault for writing without checking the documentation. I've deleted the offending comment.
I'm using .NET 4.0 so no problem with ToList(). Thanks for help, i would certainly not solve this myself :-)
1

I tried something similar and I get a passing test:

[Test] public void CollectionCountShouldBeGreaterThanZero() {
  // arrange
  string tempDir = Path.GetTempPath();
  var fileInfo = new FileInfo(tempDir + Path.DirectorySeparatorChar + "test.zip");
  File.WriteAllBytes(fileInfo.FullName, Resources.TestZipFile);

  SevenZipBase.SetLibraryPath(@"c:\7z.dll");

  // act
  ReadOnlyCollection<string> collection;
  using(var archive = new SevenZipExtractor(fileInfo.FullName))
    collection = archive.ArchiveFileNames;

  // assert
  Assert.IsTrue(collection.Count > 0);
}

2 Comments

You're using different SevenZipLib. I use SevenZipLib and you seem to be using SevenZipSharp which seems to act differently. And mine seems to behave like Jon says.
Yes, it would be interesting to look inside both to see what's going on
0

The problem is that the field you are referencing is part of archive. The archive object doesn't exist at that point because of the using closure.

You could clone the values inside the using which would give you a copy of the list instead of a reference to the list values and that would do the job.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.