c# - BlockReentrancy en ObservableCollection<T>
.net events (3)
¿Podría alguien por favor tener la amabilidad de explicarme cuál es el propósito del Método BlockReentrancy
en el ObservableCollection<T>
?
MSDN muestra lo siguiente como un ejemplo:
//The typical usage is to wrap an OnCollectionChanged call within a using scope, as in the following example:
using (BlockReentrancy())
{
// OnCollectionChanged call
}
Pero esto no parece aclararme cuál es el propósito. ¿Alguien quiere explicar?
Esta es la implementación de BlockReentrancy()
protected IDisposable BlockReentrancy()
{
this._monitor.Enter();
return this._monitor;
}
Hay otro método CheckReentrancy()
protected void CheckReentrancy()
{
if ((this._monitor.Busy && (this.CollectionChanged != null)) && (this.CollectionChanged.GetInvocationList().Length > 1))
{
throw new InvalidOperationException(SR.GetString("ObservableCollectionReentrancyNotAllowed"));
}
}
Tales métodos como ClearItems
, InsertItem
, MoveItem
, RemoveItem
, SetItem
comprueban CheckReentrancy()
antes de modificar la colección.
Por lo tanto, el siguiente código garantiza que la recopilación no se cambiará dentro del using
, sino solo si hay más de un controlador suscrito al evento CollectionChanged
.
using BlockReentrancy())
{
CollectionChanged(this, e);
}
Este ejemplo demuestra el efecto de BlockReentrancy()
private static void Main()
{
collection.CollectionChanged += CollectionCollectionChanged1;
collection.CollectionChanged += CollectionCollectionChanged2;
collection.Add(1);
}
private static void CollectionCollectionChanged1(object sender, NotifyCollectionChangedEventArgs e)
{
collection.Add(2); // this line will throw exception
}
private static void CollectionCollectionChanged2(object sender, NotifyCollectionChangedEventArgs e)
{
}
La reentrada es cuando un método hace algo, directa o indirectamente, que hace que ese método sea invocado nuevamente, posiblemente recursivamente. En este caso, el bloque que usa debe usarse dentro del delegado OnCollectionChanged si desea evitar el cambio de la colección desde el controlador; los intentos de cambiar arrojarán una excepción. Si no lo utilizó, cualquier intento de modificar la colección provocaría que se llamara nuevamente a OnCollectionChanged.
Un ObservableCollection
implementa INotifyCollectionChanged
y tiene un evento CollectionChanged
. Si hay un suscriptor a este evento, podrían modificar aún más la colección mientras la colección ya está en proceso de notificación. Dado que el evento CollectionChanged
realiza un seguimiento de los cambios exactos, esta interacción puede ser muy complicada.
Como resultado, el ObservableCollection
permite, como un caso especial, un solo suscriptor del evento CollectionChanged
para modificar la colección desde su controlador. Pero no permite modificar la colección del controlador CollectionChanged
si hay dos o más suscriptores al evento CollectionChanged
.
El par de métodos BlockReentrancy
y CheckReentancy
se utilizan para implementar esta lógica. El BlockReentrancy
se usa al inicio del método CheckReentancy
y CheckReentancy
se usa en todos los métodos que modifican la colección.