LoginSignup
9

More than 5 years have passed since last update.

WeakReference・WeakReference<T> の違いと、そこに潜む罠

Last updated at Posted at 2015-10-22

はじめに

WeakReference、使ってますか。私はあまり使っていません。その存在は知っていても、使う機会はあまりないという人は、私にかぎらず多くいるのではないでしょうか。

もちろん、WeakReference が何のためにあるかはご存知のことと思います。知らなかったという方は、岩永さんに感謝しながら、以下の記事を読んで勉強しておきましょう。

WeakReferenceWeakReference<T>

さて、ここからが本題です。

WeakReference には、System.WeakRefenence と、System.WeakReference<T> がありますが、この2つの違いは何でしょうか。

「非ジェネリックとジェネリックの違いでしょ」と思いがちですが、実はそれだけの違いではありません。WeakReference には IsAlive Target というプロパティがありますが、WeakReference<T> にはそれらはなく、代わりに TryGetTarget メソッドが追加されています。

つまり、WeakReferenceWeakReference<T> は、ジェネリクスか否かだけの違いではなく、メンバも変更されています。

WeakReference に潜む罠

とりあえず、WeakReference<T> のことは忘れて、WeakReference だけを考えます。

みなさんはどのようにして WeakReference からその参照先を取得していますか?

var ref = new WeakReference(new int[0]);

if (ref.IsAlive)
{
    DoSomething(ref.Target as int[]);
}

説明するまでもないと思いますが、このコードは参照先が存在する場合にのみ DoSomething を呼び出すというコードです。

しかし、このコードには罠があります。本当に、DoSomething を呼び出す時点で参照先は存在していると言えるでしょうか。if の条件式を評価したあと、DoSomething を呼び出す前に GC が実行された場合、参照先はもはや存在しません。

このことを考慮すると、以下のようにするのが正しいことがわかります。

var ref = new WeakReference(new int[0]);

var obj = ref.Target as int[];
if (obj != null)
{
    DoSomething(obj);
}

WeakReference<T>

では、WeakReference<T> ではどうでしょうか。WeakReference<T> には IsAliveTarget もなく、代わりに TryGetTarget があるだけですから、以下のように書くしかありません。

var ref = new WeakReference<int[]>(new int[0]);

int[] obj;
if (ref.TryGetTarget(out obj))
{
    DoSomething(obj);
}

WeakReference にあった罠は、WeakReference<T> にはありません。

先述のとおり、WeakReferenceWeakReferenc<T> では、メソッドやプロパティが異なっていますが、それは WeakReference に存在する罠が原因でしょう。そもそも、IsAlive で状態を取得したところで、次の瞬間には GC が実行されている可能性があるため、意味がありません。

まとめ

WeakReference ではなく WeakReference<T> をつかいましょう。ジェネリックでなく、罠が存在する WeakReference を使うメリットはありません。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9