Есть ли метод или какой-либо другой легкий способ проверить, есть ли ссылка на удаленный объект?
P.S. - Это просто любопытство (спи спокойно, а не в продакшн коде). Да, я знаю, что могу поймать ObjectDisposedException при попытке доступа к члену объекта.
@ nicodemus13: метод Dispose предписывает объекту освободить все ресурсы, которые он получил, но еще не освободил. Если объект никогда не удерживает ресурсы, его метод Dispose обычно не должен ничего делать; если тип объявляет void IDisposable.Dispose() {};, он может игнорировать IDisposable без дополнительных затрат на каждый экземпляр. Свойство IsDisposed, которое должно было стать истинным после любого вызова Dispose, потребовало бы добавления ненужного в противном случае логического флага к каждому экземпляру многих типов, которые в противном случае могли бы игнорировать Dispose.
Но где бы вы ни вызывали метод объекта, реализующего IDisposable, как вы можете сначала проверить, был ли он удален? Вместо того, чтобы предполагать, что это не так, и ловить исключение? Или вы каким-то образом должны управлять сроком службы, чтобы всегда знать, утилизировано оно или нет?
@ nicodemus13: обычно не следует использовать объект, не зная, что он не был и не будет удален, за исключением случаев, когда вы готовы рассматривать удаление объекта внешним кодом как сигнал для отмены любых ожидающих действий с ним . Флаг IsDisposed может помочь предотвратить трату времени кода на операции, которые не могут быть успешными, но все равно придется обрабатывать исключения в случае удаления объекта между проверкой IsDisposed и попыткой его использования.
WeakReference кажется здесь уместным. Это не совсем детектор IDipose'd, но он говорит вам, был ли он GC.
Хотя это не помогает всем IDisposable и требует заблаговременного планирования, если у вас есть System.ComponentModel.IComponent, есть событие Disposed, к которому вы можете присоединиться, как упомянуто в Ответ Моисея





Нет - реализация шаблона IDisposable по умолчанию не поддерживает его.
System.Windows.Forms.Control имеет свойство IsDisposed, которое равно установить значение true после вызова Dispose(). В ваших собственных объектах IDisposable вы можете легко создать подобное свойство.
ОП искал, есть ли уже подобное свойство у объектов, которые он не создает. Это было бы хорошей идеей для объектов, которые мы создаем, но большинство одноразовых классов в .NET не следуют этому соглашению. Ответ Дандикаса правильный.
@krillgar, в вопросе ОП нет ничего, что подтверждает ваше утверждение.
Если это не ваш класс и он не предоставляет свойство IsDisposed (или что-то подобное - это просто соглашение), то у вас нет возможности узнать.
Но если это ваш класс и вы следуете каноническая реализация IDisposable, тогда просто выставьте поле _disposed или _isDisposed как свойство и проверьте это.
Нет ничего, что позволяло бы это сделать. Вам нужно будет предоставить логическое свойство IsDisposed, которое отражает внутренний удаленный флаг.
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);
}
}
Кстати, если кто-то начинает использовать этот шаблон, он помогает определить новый интерфейс (IDisposablePlus или что-то еще), который наследуется от IDisposable и включает bool IsDisposed { get; }. Это позволяет легко узнать, какие из ваших объектов IDisposable поддерживают IsDisposed.
Я не думаю, что вы можете унаследовать интерфейс из-за того, как работает C#. Размещение интерфейса после двоеточия наследует его. Я ожидаю, что он будет реализовывать интерфейс с другой стороны.
Мне нравится объявлять объекты без их инициализации, но устанавливать для них значения по умолчанию 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
@ LarsHöppner: Суть вопроса не зависит от языка, и хорошие разработчики C#, вероятно, должны знать хотя бы достаточно VB.NET, чтобы прочитать приведенный выше код (и разработчики VB.NET также должны выучить достаточно C#, чтобы читать код C#, который не делать что-нибудь особо экзотическое).
Зачем вам делать все это вместо использования оператора Using? Это определенно существовало еще в 2013 году, когда был написан этот ответ.
На самом деле "GoodExit:" что это за 1983 год для GOTO ?? Пожалуйста, прекратите использовать это.
Это не отвечает на вопрос. В частности, после того, как inputPdf был установлен на значение (кроме Nothing), ваш ответ не показывает способа узнать, был ли inputPdf удален. Вы можете решить эту проблему с помощью частично, установив inputPdf = Nothing после утилизации. Однако это не поможет никаким переменным Другие, которые были указаны на тот же объект, что и inputPdf. То есть, если вы сделаете: inputPdf = New PdfReader, Dim pdf2 As PdfReader = inputPdf, inputPdf.Dispose, inputPdf = Nothing, все равно не будет возможности узнать, что pdf2 удален (это тот же объект, что и inputPdf).
Метод Dispose необходим для выполнения любой очистки, которая потребуется перед тем, как объект будет оставлен; если очистка не требуется, ничего делать не требуется. Требование от объекта отслеживать, был ли он удален, даже если в противном случае метод Dispose ничего бы не сделал, потребовало бы, чтобы многие объекты IDisposable добавляли флаг для очень ограниченной выгоды.
Было бы полезно, если бы IDisposable включал два свойства - одно, которое указывало, является ли объект необходима утилизация, и одно из которых указывало, что объект не был стал бесполезным по удалению. Для объектов, где удаление действительно что-то делает, оба значения будут изначально истинными, а после Dispose станут ложными. Для объектов, для удаления которых не требуется выполнять какую-либо очистку, первый метод всегда может возвращать false, а второй всегда true, без необходимости хранить флаг где-либо. Однако я не думаю, что есть какой-либо способ добавить их в .NET сейчас.
ИМХО, два флага - это перебор. Я думаю, что лучше придерживаться обычной парадигмы, когда у объекта есть единственный флаг после того, как Dispose был вызван для объекта. В противном случае вы добавляете сложность, просто чтобы знать, что определенные объекты «все еще полезны», даже если для них был вызван метод Dispose. Не стоит идти по этой дороге.
@ToolmakerSteve: Обычно флагов может быть ноль или один. Для объектов, требующих удаления, свойства "требуется удаление" и "полезно" дадут значение "истина / истина" перед удалением и "ложь / ложь" после него, но для объектов, для которых удаление не требуется, оба безоговорочно вернуть «ложь / истина». Сказать, что объект все еще требует утилизации, когда этого никогда не происходит, или что объект бесполезен, когда он всегда есть, было бы довольно неприятно. Я полагаю, что другой подход заключался бы в использовании перечислимого типа, чтобы указать, нужно ли утилизировать тип, был ли удален или просто не имеет значения.
@ToolmakerSteve: Я думаю, что основная причина, по которой IDisposable не имеет свойства Disposed, заключается в том, что было бы странно иметь объекты, в которых вызов Dispose не установил бы такое свойство в true, но требовал, чтобы объекты отслеживали, является ли Dispose вызывали в тех случаях, когда в противном случае у них не было бы причин для беспокойства, что привело бы к значительным затратам и небольшой выгоде.
Я вижу, что это старый, но я не видел ответа. Некоторые не все одноразовые объекты, такие как 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;
}
}
Хорошо знать. В частности, событие Disposed является членом интерфейса System.ComponentModel.IComponent.
Не знаю. Кажется любопытным, что на
bool IsDisposed { get; }нет декларацииSystem.IDisposable.