Объявить параметр универсального типа как деструктор? - PullRequest
0 голосов
/ 18 января 2012

У меня есть общий класс, который начинается с:

public class EntityContextFactory<T>
    where T: class, IDisposable, IObjectContextAdapter, new()

Позже в классе, когда у меня есть метод, который содержит:

            T context = HttpContext.Current.Items[objectContextKey] as T;
            if (context != null)
            {
                context.Dispose();
                GC.SuppressFinalize(context);
                HttpContext.Current.Items.Remove(objectContextKey);
            }

Я получаю предупреждение от ReSharper, в котором говорится, что GC.SuppressFinalize вызывается для типа без деструктора. Как я могу удалить эту ошибку? Я знаю, что в Dbcontexts действительно есть деструктор, потому что, когда я пишу этот тип класса не в общем, я не получаю такой ошибки. Я попытался объявить, что T реализует те же интерфейсы, что и Dbcontext, но это не сработало ...

Ответы [ 3 ]

4 голосов
/ 18 января 2012

Вы можете удалить эту ошибку, не вызывая SuppressFinalize.Не существует универсального ограничения (и, вероятно, нет ограничения ReSharper), которое вы могли бы применить, чтобы требовать финализатор.

Любой класс, имеющий финализатор, должен вызывать GC.SuppressFinalize(this); в своем Dispose.Если класс этого не делает, у него, вероятно, есть веская причина, и вам тоже не следует его называть.

1 голос
/ 20 сентября 2012

Во-первых, GC.SuppressFinalize(obj) проверяет, является ли данная ссылка ссылкой на указатель this прямого вызова метода (см. Интерактивную справку: «Параметр obj должен быть вызывающим для этого метода.») - таклюбой вызов, кроме GC.SuppressFinalize(this), вызовет исключение!

Во-вторых, вызов GC.SuppressFinalize(this) означает, что GC НЕ выполняет код завершения (экземпляр удаляется из очереди завершения).Чем короче очередь финализации, тем быстрее работает сборщик мусора ... но поскольку все объекты наследуют финализатор ...

В-третьих, вызов GC.SuppressFinalize(this) эффективно предотвратит запуск любого деструктора.Я лично считаю деструкторы запахом кода!Написание правильного кода финализатора совсем не тривиально (помните, что все ссылки могли исчезнуть ... (уже освобождены)).Кроме того, работа с неуправляемыми ресурсами должна быть выполнена с правильной реализацией IDisposable и вызовом Dispose() ДО сбора данных об объекте.Наличие финализатора - это только последняя линия защиты - когда никто не назвал Dispose().Обычно следует использовать конструкции типа using(), которые позаботятся о вызове Dispose().

Подробное описание предмета см. Правильное использование интерфейса IDisposable

Итак - сделать звонок вообще - и если - где сделать звонок?Сделайте вызов, если вы не обрабатываете неуправляемые ресурсы и поэтому не имеете деструктора.Общее место внутри Dispose() - но это не обязательно.Другой мой любимый вариант - .ctor () - хотя ссылка this еще не полностью построена ...

Предупреждение ReSharper немного вводит в заблуждение.Он появляется в двух ситуациях - когда аргумент не является вызывающим и когда вызов не находится в Dispose().В вашем конкретном случае вам не следует совершать звонок.

1 голос
/ 18 января 2012

Описание

Я не уверен, если вам нужно GC.SuppressFinalize. Обычно это используется для неуправляемых ресурсов. Сборщик мусора (GC) делает это для управляемых ресурсов без GC.SuppressFinalize. DbContext является управляемым ресурсом, и вы должны Dispose(), чтобы вместо вызова GC.SuppressFinalize.

Вы должны запретить пользователям вашего приложения напрямую вызывать метод Finalize объекта, ограничивая его область действия защищенным.

Вы можете прочитать Когда мне следует использовать GC.SuppressFinalize ()? и Когда и как использовать Располагать и завершать в C #

Дополнительная информация

...