2010-03-01 2 views
4

У меня есть объект, который имеет одноразовый объект в качестве члена.Утилизация объектов в Destructor

public class MyClass 
{ 
    private MyDisposableMember member; 

    public DoSomething 
    { 
     using (member = new MyDisposableMember()) 
     { 
      // Blah... 
     } 
    } 
} 

Там может быть много методов в MyClass, все требуя using заявление. Но что, если я это сделал?

public class MyClass 
{ 
    private MyDisposableMember member = new MyDisposableMember(); 

    public DoSomething 
    { 
     // Do things with member :) 
    } 

    ~MyClass() 
    { 
     member.Dispose(); 
    } 
} 

Как вы можете видеть, member в настоящее время расположен в деструкторе. Будет ли это работать? Есть ли проблемы с этим подходом?

+1

При первом подходе вы инстанцировании 'member' внутри каждого метода, правильно? Или как вы можете использовать его после его утилизации? –

+0

@mmyers: правильный. –

+2

@Robert, для чего цель этого участника? (если вы создаете экземпляр для каждого использования) –

ответ

9

В идеале, Dispose() должен был быть вызван до завершения. Лучше будет следовать типичному шаблону размещения и позволить пользователю правильно распоряжаться объектом() и иметь финализатор Утилизировать его , если dispose еще не был вызван.

В этом случае, поскольку вы инкапсулируете IDisposable, вам действительно не нужно реализовывать финализатор вообще. (В момент финализации ваш инкапсулированный член будет завершен, поэтому вам не нужно завершать свой объект - он просто добавляет служебные данные.) Подробнее см. Это blog article I wrote об инкапсуляции IDisposable.

+0

В C# это на самом деле называется деструктором –

+1

http://blogs.msdn.com/ericlippert/archive/2010/01/21/what-s-the-difference-between-a- destructor-and-a-finalizer.aspx Его следует назвать финализатором. –

+0

@ Rune FS: Вы технически верны - спецификация языка C#. относится к этому как деструктор. Я возьму это. Тем не менее, я лично считаю, что это плохой выбор в terminoloty, поскольку он действительно является финализатором и превращен в финализатор в терминах GC/CLR. –

7

Возможно, вы должны сделать MyClass орудие IDisposable. Внутри метода Dispose() вызовите member.Dispose();. Таким образом, программист может иметь контроль над тем, когда элемент будет удален.

+0

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

+1

@ Robert: Нет абсолютно никакой цели иметь финализатор на вашем классе, если инкапсулированный член был правильно определен. См. Мой ответ для получения подробностей ... –

+0

В конечном итоге он по-прежнему будет использоваться GC, но при этом он просто дает программисту возможность контролировать его, если захочет. – recursive

0

Единственное, что я вижу неправильно (и это не ошибка) - это тот факт, что в используемом выражении вы явно распоряжаетесь объектом в этот момент времени (когда вы вызываете свою функцию/метод). Деструктор не может быть вызван, они вызываются автоматически. Поэтому на данный момент может потребоваться некоторое время для удаления члена. Лучше реализовать интерфейс IDisposeable для MyClass.

3

НЕ ДЕЛАЙТЕ ЭТО!

ГХ будет делать это за вас (косвенно, как объект распоряжаться или другой будет содержать деструктор)

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

Еще хуже: добавление деструктора (или финализатора) к классу требует дополнительного времени при утилизации объекта (гораздо больше времени, так как объект останется в памяти по меньшей мере для одного цикла сбора данных и, возможно, даже продвинут к следующему поколению).

Это было бы совершенно бесполезно и даже обратное.

+0

Так вы говорите, что если я сделаю MyClass IDisposable, GC вызовет Dispose() автоматически? –

+0

GC не вызывает Dispose, если это то, что вы говорите. –

+0

Нет: Утилизация класса, который вы используете, существует, поскольку класс (прямо или косвенно) использует некоторый неуправляемый ресурс. И этот ресурс должен только однажды освободиться. Если вы не вызываете «Dispose» объекта, который явно содержит неуправляемый ресурс, будет финализатор этого объекта, который освобождает ресурс. – Matthias

0

Следуя шаблону Microsoft - ваш лучший выбор, так что пользователи вашего класса будут иметь полный контроль над тем, когда он будет удален.

public class MyClass : IDisposable 
{ 
    private MyDisposableMember member = new MyDisposableMember(); 

    public DoSomething 
    { 
     // Do things with member :) 
    } 

    ~MyClass() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) // Release managed resources 
     {   
      member.Dispose(); 
     } 

     // Release unmanaged resources 
    } 
} 
+2

Хотя это технически полный шаблон Dispose для IDisposable, он предназначен для инкапсуляции собственных ресурсов, а не для другого типа IDisposable. На самом деле нет причин добавлять финализатор при инкапсуляции (правильно написанной) IDisposable. Это просто добавляет ненужные накладные расходы. Для получения дополнительной информации см .: http://reedcopsey.com/2009/04/19/idisposable-part-3-encapsulating-an-idisposable-class/ –

1

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

В более общем, вы должны поместить всю логику утилизации в Dispose() и реализовать IDisposable затем использовать вас класс вместе с использованием или примерка наконец