Что-то вроде:возвращение в середине с помощью блока
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
Я считаю, что это не подходящее место для возвращения заявления, не так ли?
Что-то вроде:возвращение в середине с помощью блока
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
Я считаю, что это не подходящее место для возвращения заявления, не так ли?
Как уже указывали другие, это не проблема.
Единственный случай, из-за которого возникают проблемы, если вы возвращаетесь в середине оператора using и дополнительно возвращаете переменную using. Но опять же, это также вызовет проблемы, даже если вы не вернетесь и просто сохраните ссылку на переменную.
using (var x = new Something()) {
// not a good idea
return x;
}
Подобно тому, как плохо
Something y;
using (var x = new Something()) {
y = x;
}
Это будет работать прекрасно, так же, как возвращение в середине try{}finally{}
То есть вполне приемлемо. A с использованием инструкции гарантирует, что объект IDisposable будет размещен независимо от того, что.
От MSDN:
используя оператор гарантирует, что Dispose вызывается даже если исключение происходит во время вызова методов объекта. Вы можете добиться того же результата, поставив объект внутри блока try и затем вызывая Dispose в блоке finally; Фактически, это то, как оператор using преобразуется компилятором.
Это абсолютно нормально - проблем нет. Почему вы считаете, что это неправильно?
Оператор using - это просто синтаксический сахар для блока try/finally, и, поскольку Grzenio говорит, что также хорошо вернуться из блока try.
Выражение return будет оценено, тогда блок finally будет выполнен, после чего метод вернется.
Ответ Джеймса Каррана объясняет, о чем я думал. – tafa
Это прекрасно.
Вы, видимо, полагая, что
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
слепо переводится на:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Который, правда, было бы проблемой, и сделает using
заявление довольно бессмысленным --- что почему это нет что это.
Компилятор гарантирует, что объект будет удален до того, как управление покинет блок - независимо от того, как он покинет блок.
Я был, по-видимому. – tafa
Отличный ответ @James Curran! Но мне очень любопытно, на что он переведен. Или это только выражается в IL? (который я никогда не пытался прочитать раньше). – Bart
@Bart - я думаю об этом, оценивая выражение return во временную переменную, а затем выполняю команду, затем возвращаю временную переменную. – ToolmakerSteve
Возможно, это не 100% верно, что это приемлемо ...
Если вам случится быть гнездовые usings и возвращение во вложенном одного , это может быть небезопасно.
Возьмите это в качестве примера:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
я проходил в DataTable которая должна быть выведена в виде CSV. С возвратом в середине он записывал все строки в поток, но на выходе csv всегда отсутствовала строка (или несколько, в зависимости от размера буфера). Это сказало мне, что что-то не закрывается должным образом.
Правильный путь, чтобы убедиться, что все предыдущие usings расположены правильно:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}
код ниже показывает, как using
работает:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Выход:
't1'.
«t2» создан.
«t3» создан.
«Создано из t1, t2, t3».
't3' расположен.
't2' расположен.
't1' расположен.
Расположенные вызывается после оператора возврата, но до выхода из функции.
Просто я собирался изменить свой вопрос о том, что вы упомянули. Благодарю. – tafa
Пожалуйста, помогите мне понять, почему это плохо. Я хотел бы вернуть Stream, который я использую в вспомогательной функции для другой функции обработки изображений. Кажется, что Stream будет утилизирован, если я это сделаю? –
@JohnShedletsky В этом случае вызов функции должен быть завернут с использованием. Подобно использованию (Stream x = FuncToReturnStream()) {...} и без использования внутри FuncToReturnStream. –