C # является допустимым объектом

#c# #pointers

#c# #указатели

Вопрос:

Вы можете проверить, имеет ли объект значение null, но можете ли вы проверить, является ли объект допустимым?

 Assert.IsValid(object_name);
 

Например, объект был удален сборщиком мусора или кто-то сделал с ним удаление. Но указатель все еще указывает на этот объект.

Ответ №1:

Если объект был освобожден сборщиком мусора, у вас не будет ссылки на него по определению.

Если он был удален и это важно для достоверности объекта, тип должен обеспечить способ определения этого. (В некоторых случаях Dispose это может означать просто «сброс», например.)

Редко уместно даже допускать возможность наличия ссылки на удаленный объект, хотя — если вы используете:

 using (Foo foo = new Foo())
{
    ...
}
 

тогда объект будет удален в то же время, что foo выходит за пределы области видимости, так что это не проблема.

Ответ №2:

Если объект был удален, на него нет никакой «живой» ссылки, поэтому вы не можете получить к нему доступ (гарантируется, что нет доступного кода, который может читать / записывать объект) (это в «безопасном» коде… В «небезопасном» коде нет никакой гарантии чего-либо. Но это «небезопасно» по какой-то причине :-))

Для IDisposable объектов классы «правильно выполнены» сохраняют флаг, который они проверяют ( bool isDisposed = false в начале IsDisposed = true; в Dispose() ) в каждом методе / свойстве, и если объект уже удален, они throw new ObjectDisposedException() .

Обратите внимание, что в среде выполнения C # / .NET нет ничего, что запрещало бы «повторно запускать», повторно использовать и «повторно удалять» объект «, но это плохое написание кода (и для поддержки этого «анти-шаблона» есть даже GC.ReRegisterForFinalize для балансировкичасто GC.SuppressFinalize выполняется в Dispose() )

Если у вас есть a WeakReference и вы хотите проверить «только для статистических целей», если объект все еще доступен, вы используете WeakReference.IsValid . Если вы хотите, чтобы ссылка на объект использовалась для его использования, вы используете WeakReference.Target и проверяете, является ли возвращаемое значение null . Это очень важно!!

 var wr = new WeakReference(new List<int>());

// Right!!
var target = (List<int>)wr.Target;
if (target != null)
{
    target.Clear();
}

// Wrong!! The GC could kick in after the if and before the target = 
if (wr.IsAlive)
{
    target = (List<int>)wr.Target;
    target.Clear();
}
 

Ответ №3:

но как бы object_name собирал мусор, если бы он не был обнулен первым?

Если указатель все еще указывает на объект (согласно вашему вопросу), то нет никакого способа, которым объект будет собирать мусор

Ответ №4:

Храните свои объекты в списке слабых ссылок.

Используйте IsAlive свойство, чтобы проверить, был ли объект собран мусором.

Ответ №5:

Сборщик мусора по определению не удаляет объекты, которые «не являются мусором», то есть включают объекты, на которые ваш код содержит ссылку.

Общего способа узнать, был ли объект удален, не существует, поскольку IDisposable contract не содержит такого метода. Но у многих классов есть способ определения их состояния, например, класс SqlConnection имеет свойство State, которое возвращает ConnectionState .Закрыто на удаленном объекте.

Ответ №6:

С точки зрения GC и состояния пользовательского объекта вы можете только проверить, был ли объект перемещен между поколениями, используя

 int objectGeneration = GC.GetGeneration(objectInstance)
 

но вы не можете получить доступ к объекту GCed или проверить, был ли объект Disposed , потому Dispose() что это пользовательская реализация каждого конкретного IDisposable типа, и в очень редких случаях эти типы отображали что-то вроде флага IsDisposed, потому что в большинстве случаев это не имеет никакого смысла для потребителя объекта.

Когда вы знаете номер поколения, вы можете сделать некоторые предположения, основанные на:

Основы сборки мусора: поколения

Поколение 0.Это самое молодое поколение и содержит недолговечные объекты. Примером недолговечного объекта является временная переменная. Сборка мусора происходит наиболее часто в этом поколении. Вновь выделенные объекты образуют новое поколение объектов и неявно являются коллекциями поколения 0, если только они не являются большими объектами, и в этом случае они попадают в кучу больших объектов в коллекции поколения 2. Большинство объектов восстанавливаются для сборки мусора в поколении 0 и не сохраняются до следующего поколения.

Поколение 1. Это поколение содержит короткоживущие объекты и служит буфером между короткоживущими и долгоживущими объектами.

Поколение 2.Это поколение содержит долгоживущие объекты. Примером объекта с длительным сроком службы является объект в серверном приложении, который содержит статические данные, которые являются актуальными в течение всего процесса