2015-05-28 3 views
2

Для того, что я читал в Интернете, вы всегда должны обращаться к объектам IDisposable, как только они вам больше не нужны..Будет ли .Net call Dispose для меня в этом случае?

Этот вопрос касается конкретного случая, когда (для меня) очевидно, что объекты больше не нужны. и, возможно, Net может позвонить мне.

пример:

type Foo() = 
    let disposable:IDisposable = // create an IDisposable 
    ... 

Возникает вопрос: Как только foo типа Foo становится недоступным (кандидат для сбора мусора, никаких ссылок не указывает на него), будет disposable получить утилизировать?

Я думаю, что disposable не будут утилизировать, как только нет ссылок на foo, так как нет никакого подсчета ссылок происходит в режиме реального времени (AFAIK), но может быть когда foo получает сбор мусора .Net будет распоряжаться disposable.

На данный момент я избегаю создавать одноразовые вещи в этом месте, поскольку мне не совсем понятно, кто должен вызывать dispose и даже если .Net вызывается dispose, я не знаю, как скоро это произойдет.

+3

Нет, GC не вызывает 'Dispose' собранных предметов, GC не знает о' IDisposable' полностью , – Lee

+2

Вам необходимо реализовать IDisposable в своем классе, если он владеет некоторым ресурсом, доступным [см. Здесь] (http://www.fssnip.net/dM) для простых примеров. – Sehnsucht

+0

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

ответ

2

Вот все, что вам нужно знать о IDisposable: CLR Inside Out: Digging into IDisposable

Короче говоря, Dispose не будет вызван сборщиком мусора, но если объект имеет финализации, финализации будет называться. Все хорошо продуманные реализации IDisposable, которые содержат неуправляемые ресурсы, будут иметь финализатор, который делает то же самое, что и метод Dispose.

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

Однако в F # часто бывает легко убедиться, что объекты автоматически удаляются: просто используйте ключевое слово use вместо привязки let.

Тем не менее, это не работает в данном конкретном примере, потому что Foo является класс, что означает, что disposable не значение, а скорее поле. Это означает, что он не выходит за пределы области действия до тех пор, пока сам объект не выйдет из области видимости, но AFAIK, нет конкретной конструкции языка для поддержки этого (нет в C#).

Вот как можно реализовать Dispose идиомы для Foo:

open System 

type Foo() = 
    let disposable:IDisposable = // create an IDisposable 
    abstract member Dispose : disposing : bool -> unit 
    default this.Dispose disposing = 
     if disposing then disposable.Dispose() 
    interface IDisposable with 
     member this.Dispose() = 
      this.Dispose true 
      GC.SuppressFinalize this 

Единственная часть, которая не совсем вписывается в «стандартной» Утилизировать идиомы, что виртуальная Утилизировать метод (bool -> unit) не защищен, потому что F # не поддерживает это (AFAIK).

+0

Я попытался использовать клавиатуру 'use', но это синтаксическая ошибка. На самом деле это вдохновило меня задать этот вопрос. –

+1

@ LayGonzález Извините, я был немного быстрым на спусковом крючке; Теперь я обновил свой ответ. –

+0

Прохладный.Я буду экспериментировать с передачей одноразовых ресурсов в качестве параметров класса (если это когда-либо понадобится) и создать вместо него одноразовые объекты в чем-то, что может выйти из области видимости, например async (async позволяет использовать ключевое слово 'use'). До сих пор это довольно освещало для меня этот подход. –

4

Очевидно, что в этом случае, возможно, нет звонка в .Dispose, если вы его не попросите (замените let на use).

Если объект GC: ed (который никогда не может быть, не детерминирован и все такое), если объект имеет финализатор, тогда GC добавит объект в очередь финализатора.

Финализатор Затем поток может запустить финализации на объекте, где финализации можно бесплатно неуправляемые ресурсы, но не управляемые ресурсы, как и другие объекты .NET, реализующие IDisposable. Кроме того, в финализаторе трудно выделять ресурсы с привязкой потоков, такими как дескрипторы Windows, поскольку это неправильный поток.

И, наконец, объект may get GC: ed.

Таким образом, GC является отличным (чистым) для ресурсов чистой памяти, для других ресурсов мы используем детерминированный и явный сбор ресурсов, вызывая Dispose или используя use.

Эрик Липперт недавно написал интересный blog о чудесном мире финализаторов, который стоит проверить за более подробной информацией.

+0

«Когда все, что вы знаете, ошибочно, часть первая» Я думаю, что автор знает меня. Спасибо и спасибо за ваш ответ. Обучение C#, F # и .Net в то же время слишком много. –

3

Как уже упоминалось ранее, Dispose не будет вызываться непосредственно сборщиком мусора, хотя финализатор будет вызван, когда disposable будет собран мусором и, мы надеемся, очистит его ресурсы аналогичным образом.

К сожалению, изменение let к use не решает проблему в данном случае, так как это даст вам ошибку компилятора:

type Foo() =  
    use disposable:IDisposable = // create an IDisposable 

// error FS0523: 'use' bindings are not permitted in primary constructors 

Ваши варианты здесь:

  1. Определение disposable Внутри метод Foo

    type Foo() = 
        member this.DoSomething() = 
         use disposable:IDisposable = // create an IDisposable 
    
  2. Или сделать Foo IDisposable и толкать ответственность увода ее своим потребителям

    type Foo() =   
        let disposable:IDisposable = // create an IDisposable 
    
        interface IDisposable with 
         member this.Dispose() = disposable.Dispose() 
    
        member this.DoSomething() =()  
    
    let bar() = 
        use t = new Foo() 
        t.DoSomething() 
    
+1

Хороший момент, я пропустил это был тип. На самом деле я создал F # pr некоторое время назад для автогенерации Dispose методов для типов, а затем модифицировал компилятор, чтобы разрешить использование членов типа. Сообщество F # не одобрило, хотя PR умер ... – FuleSnabel