2010-12-10 105 views
2

我一直认为通过在using之前声明var将允许它在using之内分配,然后我仍然可以读取它之外的变量。原来我不能:-)在C#中使用并使用变量赋值内部使用

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

回答

3

乔尔龙多在他的回答中指出,集合是被CLE因为档案正在处理中。但是,将其包装在ReadonlyCollection中将不起作用,因为它不会复制包装列表。您需要手动创建这个副本:

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

工作:-) – MadBoy 2010-12-10 20:10:01

+0

是的。在这种情况下,检查文档和我的“新”理论肯定不起作用。这好多了。 – 2010-12-10 20:10:26

6

复制archive.Volumes,而不是只具有参考集合它。然后,在使用结束时处理归档时,您的收藏将不会被处置。

+0

你的意思是复制它? – MadBoy 2010-12-10 19:53:22

+0

我改变它,并且在使用之外它仍然变为0 ..我已经添加了我用于我的帖子的示例。 – MadBoy 2010-12-10 20:01:11

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> ...真正复制,而不仅仅是创建一个包装。

当然,如果你不介意,如果该方法返回一个列表,你可以只使用:

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

+0

那么为什么我在使用内部时count = 10,当外部变为0时呢? – MadBoy 2010-12-10 19:58:38

+0

我怎样才能防止它被丢弃而不使用处置? – MadBoy 2010-12-10 20:08:38

+0

@MadBoy:查看我的编辑。 – 2010-12-10 20:11:00

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

您正在使用不同的SevenZipLib。我使用SevenZipLib,你似乎正在使用SevenZipSharp,它似乎行事不同。我的行为似乎像Jon说的那样。 – MadBoy 2010-12-10 20:14:45

+0

是的,看看里面发生了什么会很有趣 – 2010-12-10 20:23:55

0

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

你可以克隆使用的内部值,它会给你一个列表的副本,而不是对列表值的引用,并且可以完成这项工作。