Могу ли я определить, называется ли объект GC.SuppressFinalize? - PullRequest
3 голосов
/ 08 января 2011

Есть ли способ определить, вызвал ли объект GC.SuppressFinalize или нет?

У меня есть объект, который выглядит примерно так (полноценный шаблон Dispose для ясности исключен):

public class ResourceWrapper {
    private readonly bool _ownsResource;
    private readonly UnmanagedResource _resource;

    public ResourceWrapper(UnmanagedResource resource, bool ownsResource) {
        _resource = resource;
        _ownsResource = ownsResource;
        if (!ownsResource)
            GC.SuppressFinalize(this);
    }
    ~ResourceWrapper() {
        if (_ownsResource)
            // clean up the unmanaged resource
    }
}

Если параметр конструктора ownsResource равен false, то финализатору будет нечего делать, поэтому кажется разумным (если немного странным) вызвать GC.SuppressFinalize прямо из конструктора.Однако, поскольку это поведение странное, мне очень хочется отметить это в XML-комментарии к документу ... и, если у меня возникает желание его прокомментировать, я должен написать для него модульный тест.

Но пока System.GC имеет методы для установки финализируемости объекта ( SuppressFinalize , ReRegisterForFinalize ), я не вижу никаких методов получить завершаемость объекта.Есть ли способ узнать, был ли вызван GC.SuppressFinalize для данного экземпляра, кроме покупки Typemock или написания моего собственного хоста CLR?

Ответы [ 3 ]

4 голосов
/ 08 января 2011

Это невозможно, GC просто не предоставляет эту информацию. Причина тому - объект может находиться не только в двух состояниях. Он также может уже находиться в очереди завершения или уже завершен.

Пользовательский хост CLR не поможет вам в этом, интерфейс хостинга не предоставляет никаких хуков в gc. Вы можете проверить, был ли вызван SuppressFinalize, когда это нужно сделать, просто проверив это в финализаторе. Войдите (быстро). Вы не можете доказать обратное.

Кстати, классы фреймов .NET этого не делают, они просто позволяют финализатору работать в любом случае.

3 голосов
/ 13 января 2011

Если вы хотите подтвердить, что завершение было подавлено, если ваш объект не владеет ресурсом, возможно, вы могли бы заставить финализатор утверждать, что он владеет ресурсом? Тест должен был бы выполнить GC.Collect и GC.WaitForPendingFinalizers, но в производственном коде не будет ничего лишнего, кроме assert (который может быть опущен в производственной сборке). Одно небольшое предостережение с утверждением: если поток, который создает объект, умирает между созданием объекта и установкой статуса владения, финализатор может работать неправильно.

С учетом вышесказанного мне интересно, будет ли лучше иметь абстрактный тип ResourceWrapper с отдельными подтипами OwnedResourceWrapper и SharedResourceWrapper, которые владеют или не владеют рассматриваемым ресурсом. Тогда у подтипа, который не владеет ресурсами, вообще не нужно иметь финализатор. Обратите внимание, что для SharedResourceWrapper может быть полезно реализовать IDisposable в качестве запрета.

2 голосов
/ 08 января 2011

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

...