Есть ли побочные эффекты при возврате изнутри оператора using ()?

125

Возвращение значения методы из внутри с помощью заявления , которое получает DataContext , кажется, всегда работает штраф , как это:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

Но я всегда чувствую , что я должен закрывать что - то прежде , чем я вырваться из использования скобок, например , путь определения сделки , прежде чем с помощью заявления, получить его значение в скобках, а затем возвращаюсь после скобок.

Было бы лучше определить и вернуть переменную вне скобок или каким-либо образом сэкономить ресурсы?

Эдвард Тангуай
источник
1
Было бы интересно посмотреть на общий IL для вариантов этого. Я подозреваю, что в сгенерированном IL будет небольшая разница. Обычно я бы даже не стал объявлять транзакцию var - просто вернул результат выражения.
Jonesie 03

Ответы:

164

Нет, я думаю, так понятнее. Не волнуйтесь, Disposeбудет по-прежнему вызываться «на выходе» - и только после того, как возвращаемое значение будет полностью вычислено. Если в какой-то момент возникает исключение (включая оценку возвращаемого значения), оно Disposeвсе равно будет вызываться.

Хотя вы, безусловно, можете выбрать более длинный путь, это две дополнительные строки, которые просто добавляют беспорядка и дополнительный контекст, который нужно отслеживать (мысленно). Фактически, вам действительно не нужна дополнительная локальная переменная, хотя это может быть удобно с точки зрения отладки. Вы могли просто иметь:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

В самом деле, у меня даже может возникнуть соблазн использовать точечную нотацию и поместить Whereусловие в SingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}
Джон Скит
источник
2
Так как это вы @jon, это все еще безопасно, если внутри блока using возникает исключение?
Дэйв Арчер,
6
да. using - это просто синтаксический сахар для конструкции try / finally
Митч Уит
@David: Как говорит Митч, все в порядке - я обновил ответ, чтобы было понятнее :)
Джон Скит,
2
Зачем использовать OrderByDescending в сочетании с SingleOrDefault?
erikkallen 04
2
@erikkallen: LINQ, к сожалению, не имеет «MaxBy», поэтому вы не можете получить строку с максимальным значением. Для LINQ to Objects вы можете довольно легко написать свой собственный, но я не уверен, что лучше сделать это в данном случае. Что бы вы предложили вместо этого?
Джон Скит,
32

Посмотри на это

Понимание оператора using в C #

CLR преобразует ваш код в MSIL. И оператор using переводится в блок try and finally. Вот как оператор using представлен в IL. Оператор using переводится на три части: приобретение, использование и выбытие. Ресурс сначала приобретается, затем использование включается в оператор try с предложением finally. Затем объект удаляется в предложении finally.

Адриан Стандер
источник
4
Интересная догадка. Спасибо.
Кангкан, 03
1
Это переводит вопрос к следующему: есть ли побочные эффекты возврата из блока try-finally?
Хенк Холтерман,
3
Нет, всегда будет называться окончательный. techinterviews.com/interview-questions-for-c-developers
Адриан Стандер,
6

Там нет ни одного побочных эффектов возвращения из внутри using()заявления.

Другой вопрос, делает ли он наиболее читаемый код.

Митч Уит
источник
0

Думаю, все равно. В коде нет ничего плохого. Платформе .NET безразлично, где создается объект. Важно то, есть ли на него ссылка или нет.

Kerido
источник
-1

Да, может быть побочный эффект. Например, если вы используете тот же метод в методе действия ASP.NET MVC, вы получите следующую ошибку: «Экземпляр ObjectContext удален и больше не может использоваться для операций, требующих подключения»

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}
usefulBee
источник
2
если вы определите транзакцию вне оператора using, вы получите ту же ошибку. using ключевое слово не имеет отношения к этому случаю.
Коста