Reputation: 11104
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;
}
Upvotes: 3
Views: 2157
Reputation: 2738
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.
Upvotes: 0
Reputation: 10722
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);
}
Upvotes: 1
Reputation: 144136
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());
}
Upvotes: 7
Reputation: 1500785
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.)
Upvotes: 2
Reputation: 7586
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.
Upvotes: 6