在C#中使用使用和获取内部变量

时间:2010-12-10 19:48:07

标签: c# using

我一直认为通过在using之前声明var将允许在using内分配,然后我仍然可以读取它之外的变量。结果我不能: - )

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

任何使其无法停止使用using

的方法

完整的测试方法:

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;
}

5 个答案:

答案 0 :(得分:6)

复制archive.Volumes而不仅仅是集合引用它。然后,当在使用结束时处理存档时,您的收藏将不会被处理。

答案 1 :(得分:5)

正如Joel Rondeau在他的回答中所指出的那样,该档案正在被清理,因为存档正在被处理掉。但是,将其包装在ReadonlyCollection中将不起作用,因为这不会复制包装列表。您需要手动创建此副本:

ReadOnlyCollection<string> collection;
using (var archive = new SevenZipArchive(varRarFileName))
{
    collection = new ReadOnlyCollection<string>(archive.Volumes.ToList());
}

答案 2 :(得分:2)

你绝对可以从变量中读取。在明确赋值方面没有问题,或者你会遇到编译时错误。例如,这很好:

using System;
using System.IO;

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

这绝对没问题。

现在,如果SevenZipArchive返回ReadOnlyCollection<string>,我通常希望在归档归档后仍然有效。但是,ReadOnlyCollection<T>只是另一个集合的包装器...如果通过处置archive使该集合失效,那肯定会解释一些事情。

不幸的是,Joel建议的复制集合的方法只是创建另一个包装器 - 它将向第一个包装器询问计数,然后询问原始(无效的)集合。

这是一种应该有效的方法:

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;
}

请注意ToList()的额外电话。这将强制将集合首先复制到List<string> ...真正复制,而不仅仅是创建包装器。

当然,如果您不介意该方法返回List,您可以使用:

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;
}

...然后当您不需要额外的诊断时:

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

(顺便说一句,我假设您使用的是.NET 3.5或更高版本,以使用ToList扩展方法。)

答案 3 :(得分:1)

我尝试了类似的东西,我得到了通过测试:

[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);
}

答案 4 :(得分:0)

问题是您引用的字段是存档的一部分。由于使用了闭包,归档对象在那时不存在。

您可以克隆使用中的值,这将为您提供列表的副本,而不是对列表值的引用,并且可以完成此任务。