Что происходит с объектом IDisposable после его возвращения? - PullRequest
4 голосов
/ 08 июня 2010

У меня есть функция C #, которая переворачивает ориентацию DataSet:

static DataSet FlipDataSet(DataSet my_DataSet)
    {
        using (DataSet ds = new DataSet())
        {
            foreach (DataTable dt in my_DataSet.Tables)
            {
                DataTable table = new DataTable();
                for (int i = 0; i <= dt.Rows.Count; i++)
                {
                    table.Columns.Add(Convert.ToString(i));
                }
                DataRow r = null;
                for (int k = 0; k < dt.Columns.Count; k++)
                {
                    r = table.NewRow();
                    r[0] = dt.Columns[k].ToString();
                    for (int j = 1; j <= dt.Rows.Count; j++)
                        r[j] = dt.Rows[j - 1][k];
                    table.Rows.Add(r);
                }
                ds.Tables.Add(table);
                table.Dispose();
            }
            return ds;
        }
    }

Я изменил этот код из фрагмента, обнаруженного во внутренних сетях, чтобы обернуть созданный DataSet в оператор using и явно избавитьсяIDisposable объекты, которые он создает.Мой вопрос: что происходит с DataSet («ds» в приведенном выше коде), когда он возвращается, с точки зрения утилизации?Я не могу явно вызвать .Dispose () для ds после того, как я его верну, очевидно, поэтому .NET возвращает значение и затем удаляет его должным образом, или я что-то упустил полностью?

Ответы [ 6 ]

12 голосов
/ 08 июня 2010

Вы, вероятно, не хотите этого делать. DataSet удаляется при выходе из блока using независимо от того, как выходит из блока (обычное исключение при выходе, возврате или выбрасывании), что означает, что возвращаемое вами значение будет удалено и будет в основном непригодным для использования. звонящему.

Правильнее всего сделать, чтобы в этой функции не было блока using. Блок using должен быть в вызывающей стороне.

5 голосов
/ 08 июня 2010

ds DataSet будет удален, как только вы выйдете из блока using, так что вы вернете удаленного DataSet вызывающей стороне.

Почему вы говорите, что не можете позвонить Dispose на DataSet после того, как вернули его? Я подозреваю, что это именно то, что вам нужно сделать.

Удалите блок using из вашего метода FlipDataSet, а затем избавьтесь от возвращенного DataSet в вызывающем коде, предпочтительно заключив его в блок using.

3 голосов
/ 08 июня 2010

У вас уже есть действительно хороший ответ, но я хочу представить другой подход.

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

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

3 голосов
/ 08 июня 2010

Как уже упоминалось в другом ответе, вы вернете удаленный набор данных.Это "плохая вещь" TM .

Я очень сильно верю, что каждый IDisposable должен всегда быть заключен в блок использования.Тем не менее, иногда хитрость заключается именно в том, где используется этот блок.Для функций, которые возвращают IDisposable, вы просто создаете объект как обычно.Блок using оборачивает строку, вызываемую функцией.

0 голосов
/ 12 марта 2015

Даже если ваш вызывающий объект избавляется от возвращенного набора данных, заключая вызов функции в оператор using, я думаю, что вы все равно должны иметь блок try / catch внутри своей функции, чтобы убедиться, что ваш набор данных расположен в блоке catch и повторно бросить исключение, если это произойдет.

Однако код new DataTable() должен быть заключен в оператор использования

0 голосов
/ 08 июня 2010

Как говорит LukeH, возможно, в вашем текущем коде есть ошибка. Если вы удалите этот оператор using для DataSet и вернете его, тогда вызывающий ваш метод должен Dispose правильно его обработать, как и должно быть, поскольку ваш код не может сказать, когда он утилизировать.

...