Использование с использованием и получение переменной, назначенной внутри использования в C # - PullRequest
2 голосов
/ 10 декабря 2010

Я всегда думал, что, объявив var перед 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 ]

6 голосов
/ 10 декабря 2010

Скопируйте archive.Volumes вместо того, чтобы указывать коллекцию Затем, когда архив будет удален в конце использования, ваша коллекция не будет уничтожена.

5 голосов
/ 10 декабря 2010

Как указывает Джоэл Рондо в своем ответе, коллекция очищается по мере удаления архива.Однако перенос в ReadonlyCollection не сработает, так как это не копирует свернутый список.Вам необходимо создать эту копию вручную:

ReadOnlyCollection<string> collection;
using (var archive = new SevenZipArchive(varRarFileName))
{
    collection = new ReadOnlyCollection<string>(archive.Volumes.ToList());
}
2 голосов
/ 10 декабря 2010

Вы можете определенно все еще читать из переменной.Там нет проблем с точки зрения определенного назначения, иначе вы получите ошибку во время компиляции.Например, это нормально:

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, это, безусловно, объяснит.

К сожалению, Джоэл предложил способ копирования коллекции.только создает другую обертку - которая будет запрашивать у первой обертки счетчик, в свою очередь запрашивая исходную (недействительную) коллекцию.

Вот один подход, который должен работать:

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.)

1 голос
/ 10 декабря 2010

Я попробовал что-то подобное, и я проходил тестирование:

[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 голосов
/ 11 декабря 2010

Проблема в том, что поле, на которое вы ссылаетесь, является частью архива. Архивный объект на тот момент не существует из-за использования закрытия.

Вы можете клонировать значения внутри использования, что даст вам копию списка вместо ссылки на значения списка, и это сделает работу.

...