在C#中使用using并获取使用中的变量赋值

3

我一直认为在using之前声明变量可以允许在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个回答

7

正如Joel Rondeau在他的回答中所指出的那样,随着存档文件的处理,集合正在被清除。然而,将其包装在ReadonlyCollection中不起作用,因为这不会复制包装的列表。您需要手动创建此副本:

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

是的。我查阅了文档,我的“新”理论在这种情况下肯定行不通。这个方法好多了。 - Joel Rondeau

6

拷贝archive.Volumes而不仅仅是让集合引用它。这样当using结束时,archive被释放,但你的集合不会被释放。


我已经将其更改为那样,但在使用外部时仍然为0。我已经在我的帖子中添加了使用示例。 - MadBoy

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扩展方法。)

那么为什么在 using 内部时我得到 count = 10,而在外部时它变成了 0 呢? - MadBoy
除了不使用disposing,我该如何防止它被处理? - MadBoy
是的,我的错,我在没有检查文档的情况下编写了代码。我已经删除了有问题的注释。 - Joel Rondeau
我使用的是.NET 4.0,所以ToList()没有问题。感谢您的帮助,我肯定自己解决不了这个问题 :-) - MadBoy

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

你正在使用不同的SevenZipLib。我使用的是SevenZipLib,而你似乎正在使用表现不同的SevenZipSharp。我的表现好像和Jon所说的一样。 - MadBoy
是的,看看两者内部发生了什么会很有趣。 - Luke Hutton

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接