Чи є побічні ефекти повернення зсередини за допомогою () заяви?


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
Можливо, буде цікаво переглянути загальний ІЛ для варіантів цього. Я підозрюю, що різниця в генерованому ІР буде незначною. Я зазвичай не хотів би навіть задекларувати оголошення транзакції var - просто поверніть результат виразу.
Jonesie

Відповіді:


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, чи це все-таки безпечно, якщо виняток потрапляє всередину використовуючого блоку?
Дейв Арчер

6
так. використання просто синтаксичного цукру для спроби / нарешті побудови
Мітч Пшеничний

@David: Як каже Мітч, це добре - я оновив відповідь, щоб зробити це зрозуміліше :)
Джон Скіт

2
Навіщо використовувати OrderByDescending у поєднанні з SingleOrDefault?
erikkallen

2
@erikkallen: LINQ, на жаль, не має "MaxBy", тому ви не можете отримати рядок з максимальним значенням. Для LINQ to Objects ви можете написати своє власне досить легко, але я не впевнений у кращому способі зробити це в цьому випадку. Що б ви запропонували замість цього?
Джон Скіт

32

Погляньте на це

Розуміння висловлювання "використання" в C #

CLR перетворює ваш код у MSIL. І оператор using переводиться на спробу і остаточно блокує. Ось так представлений використовуваний оператор в IL. Використовуючий оператор перекладається на три частини: придбання, використання та розпорядження. Спочатку ресурс набувається, потім використання вкладається у спробу оператора з остаточно застереженням. Потім об'єкт розміщується в остаточному пункті.


4
Цікаве розуміння. Дякую.
Кангкан

1
Це перекладає питання на: Будь-які побічні ефекти повернення з пробного блоку спробу?
Хенк Холтерман

3
Ні, нарешті завжди буде покликано. techinterviews.com/interview-questions-for-c-developers
Adriaan Stander

6

Там немає жодного побічних ефектів повернення з всередині using()заяви.

Чи є він найбільш читабельним кодом - це ще одна дискусія.


0

Я думаю, все одно. У коді немає нічого поганого. .NET Framework не хвилюється, де створений об'єкт. Важливе значення - це посилання чи ні.


-1

Так, побічний ефект може бути. Наприклад, якщо ви використовуєте ту саму техніку в методі ASP.NET MVC Action, ви отримаєте таку помилку: "Екземпляр 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);
    }
}

2
якщо ви визначите транзакцію поза використанням оператора, ви отримаєте ту ж помилку. використання ключового слова в цьому випадку не пов'язане.
Коста
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.