2013-02-13 3 views
8

Considerate questo codice:Come ottenere la destinazione di un riferimento debole in modo sicuro

var weakRef = new WeakReference(new StringBuilder("Mehran")); 
if (weakRef.IsAlive) 
{ 
    // Garbage Collection might happen. 
    Console.WriteLine((weakRef.Target as StringBuilder).ToString()); 
} 

E 'possibile per GC.Collect a correre dopo aver controllato weakRef.IsAlive e prima di usare il weakRef.Target.

Mi sbaglio con questo? Se è possibile, c'è un modo sicuro per farlo?

Ad esempio un'API come weakRef.GetTargetIfIsAlive() sarebbe appropriata.

+1

Controlla http://msdn.microsoft.com/en-gb/library/ms404247.aspx –

+1

Dovresti prima eseguire il cast su un riferimento forte e quindi cercare "null". Non c'è modo di assicurare che il tuo riferimento forte non sarà nullo in anticipo. –

risposta

12

Tale API esiste già; weakRef.Target restituisce null se l'oggetto è già stato raccolto.

StringBuilder sb = weakRef.Target as StringBuilder; 
if (sb != null) 
{ 
    Console.WriteLine(sb.ToString()); 
} 
1

Prendere una copia locale della destinazione e verificare la presenza di null.

WeakReference.Target restituirà null se il bersaglio è stato raccolto ma sei preoccupazione è che si tratta di raccolte tra il .IsAlive controllo e ottenere l'obiettivo.

var weakRef = new WeakReference(new StringBuilder("Mehran")); 

if (weakRef.IsAlive) 
{ 
    var stringBuilder = weakRef.Target as StringBuilder; 

    if (stringBuilder != null) 
    { 
     Console.WriteLine(stringBuilder.ToString()); 
    } 
} 

Console.WriteLine((weakRef.Target as StringBuilder).ToString()); sarà un'eccezione di riferimento null se il cast non riesce.

+0

Mi chiedevo perché è necessario controllare 'weakRef.IsAlive', @supercat ha risposto alla domanda, quindi penso che non sia necessario controllarlo. – mehrandvd

+1

@mehrandvd Potrebbe non essere necessario, l'ho usato solo in questo esempio poiché era basato sulla tua domanda originale. Non può fare alcun danno per usarlo, ma sì, è probabilmente un controllo inutile dato il cast 'as' e il controllo nullo su' .Target'. –

+1

@TrevorPilley: usare 'IsAlive' su un' WeakReference' se un valore 'true' significherebbe che uno vuole recuperare il target è inutile. È possibile che con alcuni garbage collector, usando 'if (wr1.IsAlive && wr2.IsAlive && wr3.IsAlive) {Foo wt1 = wr1.Target come Foo, wt2 = wr2.Target come Foo, wt3 = wr3.Target as Foo; if (wr1! = null && wr2! = null && wr3! = null) {... usa tutte e tre le cose ...} 'potrebbe essere utile se ad es. un simultaneo garbage collector ha funzionato tenendo traccia di se un riferimento a qualcosa è stato creato dall'ultimo GC. Su un simile GC, se wr3 fosse morto ma wr1 e wr2 erano ancora in vita ... – supercat

9

La proprietà IsAlive non esiste per il vantaggio del codice che vorrà utilizzare il target se è vivo, ma piuttosto per il beneficio del codice che vuole scoprire se l'obiettivo è morto ma non sarebbe interessato nell'accedervi in ​​ogni caso. Se il codice dovesse testare Target contro null, ciò farebbe sì che Target abbia momentaneamente un riferimento con radice forte (il codice che sta verificando con null), ed è possibile che l'atto di generare un tale riferimento radicato possa impedire che l'oggetto venga raccolto quando altrimenti sarebbe. Se il codice non è interessato a Target tranne per scoprire se è stato ancora invalidato, non c'è motivo per il codice di ottenere il riferimento. Può semplicemente testare IsAlive invece, e prendere le misure appropriate se restituisce false.

+0

Mi chiedevo perché esista "IsAlive". Questa è una risposta molto intelligente, grazie. – mehrandvd

+1

@mehrandvd: Non è difficile immaginare un GC concorrente in cui l'atto di recuperare il 'Target' da un' WeakReference' impedirebbe che quell'oggetto venga raccolto nel ciclo successivo * anche se il riferimento è stato immediatamente scartato *.Su un sistema del genere, il codice che voleva prendere qualche azione non appena un oggetto non era più necessario e usava 'Target' piuttosto che' IsAlive' poteva finire per mantenere vivo l'oggetto in questione. – supercat