Как узнать, удалена ли ссылка на объект IDisposable?
-
08-07-2019 - |
Вопрос
Есть ли метод или какой-то другой легкий способ проверить, относится ли ссылка к удаленному объекту?
P.S.— Это просто курьёз (спите спокойно, а не в продакшен-коде).Да, я знаю, что могу поймать ObjectDisposedException
при попытке доступа к члену объекта.
Решение
Это зависит от того, есть IDisposable
объекты, позволяющие вызывать Dispose
метод столько, сколько вы хотите, и есть IDisposable
предметы, которые бросают ObjectDisposedException
.В таком случае эти объекты должны отслеживать состояние (обычно реализуется с помощью частного логического поля). isDisposed
).
Другие советы
Нет — реализация шаблона IDisposable по умолчанию не поддерживает его.
System.Windows.Forms.Control
имеет IsDisposed
имущество, которое является установить значение true после Dispose()
называется.В собственных объектах IDisposable вы можете легко создать подобное свойство.
Нет ничего встроенного, что позволило бы это сделать.Вам нужно будет предоставить логическое свойство IsDispose, которое отражает внутренний удаленный флаг.
public class SimpleCleanup : IDisposable
{
private bool disposed = false;
public bool IsDisposed
{
get
{
return disposed;
}
}
public SimpleCleanup()
{
this.handle = /*...*/;
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// free only managed resources here
}
// free unmanaged resources here
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
Если это не ваш класс и он не предоставляет свойство IsDispose (или что-то подобное — имя — это просто соглашение), то у вас нет возможности узнать об этом.
Но если это ваш класс и вы следуете каноническая реализация IDisposable, затем просто выставьте поле _dispose или _isDispose как свойство и проверьте это.
А Dispose
метод необходим для выполнения любой очистки, которая потребуется перед удалением объекта;если очистка не требуется, ничего делать не требуется.Требование к объекту отслеживать, был ли он удален, даже если Dispose
в противном случае метод ничего бы не сделал, потребовал бы много IDisposable
объекты для добавления флага с очень ограниченной выгодой.
Возможно, это было бы полезно, если бы IDisposable
включало два свойства: одно указывало, является ли объект необходима утилизация, и один из которых указывал на то, что объект не был стал бесполезным путем утилизации.Для объектов, где удаление действительно что-то делает, оба значения изначально будут истинными, а после станут ложными. Dispose
.Для объектов, для которых при удалении не требуется никакой очистки, первый метод всегда может возвращать false, а второй всегда возвращать true, без необходимости где-либо хранить флаг.Однако я не думаю, что сейчас их можно каким-либо образом добавить в .NET.
Вижу, это старо, но ответа я не увидел.Некоторые не все одноразовые объекты, такие как DataSet, имеют удаленное событие, которое вы можете прикрепить.
class DisposeSample : IDisposable
{
DataSet myDataSet = new DataSet();
private bool _isDisposed;
public DisposeSample()
{
// attach dispose event for myDataSet
myDataSet.Disposed += MyDataSet_Disposed;
}
private void MyDataSet_Disposed(object sender, EventArgs e)
{
//Event triggers when myDataSet is disposed
_isDisposed = true; // set private bool variable as true
}
public void Dispose()
{
if (!_isDisposed) // only dispose if has not been disposed;
myDataSet?.Dispose(); // only dispose if myDataSet is not null;
}
}
Мне нравится объявлять объекты без их инициализации, но устанавливать для них значения по умолчанию: Nothing
.Затем в конце цикла я пишу:
If anObject IsNot Nothing Then anObject.Dispose()
Вот полный образец:
Public Sub Example()
Dim inputPdf As PdfReader = Nothing, inputDoc As Document = Nothing, outputWriter As PdfWriter = Nothing
'code goes here that may or may not end up using all three objects,
' such as when I see that there aren't enough pages in the pdf once I open
' the pdfreader and then abort by jumping to my cleanup routine using a goto ..
GoodExit:
If inputPdf IsNot Nothing Then inputPdf.Dispose()
If inputDoc IsNot Nothing Then inputDoc.Dispose()
If outputWriter IsNot Nothing Then outputWriter.Dispose()
End Sub
Это также отлично подходит для размещения основных объектов в начале процедуры и использования их внутри процедуры. Try
рутину, а затем утилизировать их в Finally
блокировать:
Private Sub Test()
Dim aForm As System.Windows.Forms.Form = Nothing
Try
Dim sName As String = aForm.Name 'null ref should occur
Catch ex As Exception
'got null exception, no doubt
Finally
'proper disposal occurs, error or no error, initialized or not..
If aForm IsNot Nothing Then aForm.Dispose()
End Try
End Sub