2011-06-06 19 views
23

¿Podría alguien tener la amabilidad de explicarme cuál es el propósito del método BlockReentrancy en el ObservableCollection<T>?BlockReentrancy en ObservableCollection <T>

MSDN muestra el siguiente 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 aclarar para mí lo que es el propósito. ¿Alguien quiere explicar?

+0

Pronunciarlo 'BlockReëntrancy' –

Respuesta

26

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 recopilación del controlador CollectionChangedsi hay dos o más suscriptores en el 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 OnCollectionChanged y CheckReentancy se usa en todos los métodos que modifican la colección.

+0

¿Se usa para admitir la seguridad del subproceso? – deathrace

+0

Muy interesante, que la documentación de MSDN no menciona este pequeño hecho, que CheckReentrancy evitará la reentrada solo cuando haya más de un controlador asociado al evento CollectionChanged. – treaschf

+1

"no permite modificar la colección del controlador CollectionChanged si hay dos o más suscriptores al evento CollectionChanged." ¿Qué sucede si solo hay un suscriptor pero hay dos subprocesos de trabajo que modifican la colección? En ese caso, ¿debo usar el bloqueo de antera para bloquear las operaciones como Insertar y quitar y también bloquear el controlador OnCollectionChanged? – Felix

11

Esta es la aplicació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 cheque CheckReentrancy() antes de modificar colección.

Por lo tanto, el siguiente código garantiza que la recopilación no se cambiará dentro de using, pero 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) 
{ 
} 
+1

Su código de demostración arrojará una' StackOverflowException' no una 'InvalidOperationException'. En este caso, la reentrada no se está verificando. Ver mi respuesta –

+0

@Rick Sladkey - tienes razón. –

2

reentrancia es cuando un método hace algo directa o indirectamente, que provoca que el método que se invoca de nuevo, posiblemente de forma recursiva. 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.

Cuestiones relacionadas