texto - textbox bloqueado c#
Los campos de solo lectura se vuelven nulos cuando se eliminan del finalizador (3)
Tengo la siguiente clase. Ahora, a veces, la instrucción de bloqueo está lanzando una ArgumentNullException
y, en ese caso, puedo ver en el depurador que el objeto disposelock
es realmente nulo.
Como puedo ver que la eliminación es falsa, sé que el método se activa desde Finalizer.
Pero, ¿cómo puede suceder esto? Se define como de solo lectura y obtiene su valor cuando se crea el objeto.
PD: Sé que este no es un buen patrón, pero es parte de un código dado, y simplemente no puedo explicar por qué esto se vuelve nulo.
public abstract class DisposableMarshalByRefObject : MarshalByRefObject, IDisposable
{
private readonly object disposeLock = new object();
/// </summary>
~DisposableMarshalByRefObject()
{
Dispose(false);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing) //disposing = false,=> finalizer
{
lock (disposeLock) //ArgumentNull Exception !
{
....
}
}
}
En la recolección de basura el orden de esa recolección no está definido:
- Primero se recoge esto.
- Siguiente
disposeLock
se recopila
O
- En primer
disposeLock
se recoge eldisposeLock
- A continuación se recoge esto.
Por lo tanto, no utilice ningún campo de referencia (las estructuras como int
, bool
, etc. son seguras) en Dispose(false);
protected virtual void Dispose(bool disposing) {
if (disposing) {
// Explicit disposing: it''s safe to use disposeLock
lock (disposeLock) {
...
}
}
else {
// Garbage collection: there''s no guarantee that disposeLock has not been collected
}
}
Todas las respuestas existentes, excepto la respuesta de reflexión, son falsas. El GC no establece referencias a nulas cuando recopila objetos. El acceso a objetos no falla falsamente debido al GC. El orden de finalización no está definido, pero todas las referencias de objetos que existen continúan existiendo y son válidas.
Mi conjetura para lo que sucedió: el constructor fue abortado antes de que se inicializara el campo. Eso dejó el campo null
. El finalizador luego lo encontró así.
Un constructor puede ser abortado lanzando una excepción, o llamando a Thread.Abort
que es malo.
En la recolección de basura el orden de esa recolección no está definido
El orden de recolección no es observable (excepto a través de referencias débiles ...). El orden de finalización es observable, pero no con la instrucción de lock
porque los objetos no pierden la capacidad de sincronizar cuando se finalizan.
Ya que has acentuado de readonly
, una pequeña aclaración al respecto. El tiempo de ejecución no impide la modificación de los campos de readonly
. Independientemente de la readonly
de C # se convierte en initonly
de initonly
en IL.
Por ejemplo, puede modificar fácilmente el campo de readonly
utilizando la reflexión:
class A
{
private readonly int bar;
public A()
{
bar = 1;
}
public void Foo()
{
Console.WriteLine(bar);
}
}
var a = new A();
a.Foo(); // displays "1"
a.GetType().GetField("bar", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(a, 2);
a.Foo(); // displays "2"
Por supuesto, esto no significa que debas probar estos campos en null
cada vez, pero podría haber casos en los que el campo de readonly
se modifique (te has enfrentado a uno de ellos).
Como nota al margen. ¿Realmente necesitas finalizador? Quiero decir, ¿hay verdaderos recursos no administrados?