LoginSignup
0
1

More than 3 years have passed since last update.

C#のActionは途中でExceptionを起こすと中断される

Posted at

思てたんとちがう!

C#Actionをコールバックのリスナとして利用していたところ「思てたんとちがう!」という挙動があったので、改めて検証しました。
Unity.NET 4.xで実行していますが、C#ならどのプラットフォームでも同じことが起こると思います。

テストコード

テストコード
// コールバック用のリスナー
public event Action OnSomething;

private void Start()
{
    // コールバックをそれぞれ登録
    OnSomething += OnSomething1;
    OnSomething += OnSomething2;
    OnSomething += OnSomething3;

    // イベントを実行
    OnSomething?.Invoke();
}

private void OnSomething1()
{
    Debug.Log("1");
}

private void OnSomething2()
{
    throw new NotImplementedException();
}

private void OnSomething3()
{
    Debug.Log("3");
}

このコードを実行するとこうなります。

ログ
1
NotImplementedException: The method or operation is not implemented.

本来ならばOnSomething1〜3は独立のため、2でExceptionが起きても3が実行されてほしいところですが、出力されていません。

こんな感じでtry-catchしてあげると3も実行されます。

try-catch
private void OnSomething2()
{
    try
    {
        throw new NotImplementedException();
    }
    catch (Exception e)
    {
        Debug.LogException(e);
    }
}
ログ
1
NotImplementedException: The method or operation is not implemented.
3

何が怖いか

「コールバック公開しておくから、誰でも好きにイベント登録しといてくれよな!」というのがわりと一般的な使い方と思いますが、この挙動だと「他のところで登録した誰かがthrowしたら自分のところにイベントが来なくなる(しかもそれを知ることすらできない)」というなかなか恐ろしいことになります。

C#Actionは他にもラムダ式でイベント登録すると解除できなかったり、いろいろ「コワ〜」な挙動が多いです。それすらもなかった昔よりはマシになっているだろうと言われればそうなのですが……。

なにはともあれ、良い子はイベント購読側で、イベントを購読しているという状態をインスタンスとして保持・破棄できるReactiveExtensionとかUniRx使おうね!1 という話でした。

おしまい。


  1. とはいえRxもまだ人類には早すぎる代物感がある。 

0
1
0

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
0
1