Open2
HatopopoMemo

UniTaskのCancellationTokenSourceでCancelする際の処理
asyncメソッド実行時にCancellationTokenをリレーしていくが、具体どこでOperationCanceledException
が吐かれるのかを改めて調べた。
結論 : Cancel処理が行われた、次の await
が呼ばれる瞬間
この結論さえ覚えておけばエラーハンドリングも容易にできそう。
実験
private CancellationTokenSource _cts;
private async void Start()
{
_cts = new CancellationTokenSource();
Debug.Log($"{nameof(TokenTest)}.{nameof(Start)}");
await AsyncMethod(_cts.Token);
Debug.Log($"end {nameof(AsyncMethod)}");
await UniTask.Delay(1, cancellationToken: _cts.Token);
Debug.Log("Hello,,,");
}
private async UniTask AsyncMethod(CancellationToken token)
{
Debug.Log($"{nameof(AsyncMethod)}");
await UniTask.Delay(1, cancellationToken: token);
Debug.Log("Cancel");
_cts.Cancel();
Debug.Log("Canceled");
}
この場合のログは AsyncMethod
が完了した際の end AsyncMethod
までのログが出て、OperationCanceledException
が呼ばれた。
よって、CancellationTokenSource.Cancel()
が呼ばれたタイミングでは同期メソッドのキャンセルはされずに、次のawaitまでは実行されることがわかる。

C# Lazy<T> について
遅延評価を行うことができるクラス
Lazy<T>()
using System;
Lazy<string> instance = new(() => "Lazy");
Console.WriteLine(instance.IsValueCreated); // false
Console.WriteLine(instance.Value); // Lazy
Console.WriteLine(instance.IsValueCreated); // true
初めて値へアクセスする際にインスタンスが作られる = コンストラクタが走る
Lazy<T>(Func<T> valueFactory)
- 初期化時に呼ばれるメソッドを登録することができる = factoryMethod
- ここで new T(args) をしてねってこと。
- 要は遅延評価
- 重たいインスタンスだが、親インスタンスと同時に作成する必要がなければこっちで作るでもアリかも。
つまり、
// Field
HogeClass instance { get; set; }
// Method
if(instance == null){
instance = new HogeClass();
}
instance.Value;
これとか、
public HogeClass Instance => _instance;
private HogeClass _instance ??= new HogeClass();
これが必要なくなる
ちょっと応用
Lazy<T>(bool isThreadSafe)
- スレッドセーフで作ることができる
- 非同期を多用しているならtrueのが良き
Lazy<T>(LazyThreadSafetyMode mode)
- 初期化時のモード指定
- None
- デフォルト
- 軽い
- PublicationOnly
- 初期化メソッドは各スレッドで実行されるが有効なのは最初にインスタンス生成が行えたもののみ。
- 実質的なスレッドセーフ
- ExecutionAndPublication
- 完全なスレッドセーフ
-
isThreadSafe
をtrue
に指定することで内部的にこのパラメータが指定される - デッドロックに注意
- None
単一の値として扱うなら isThreadSafe
を true
にして運用するのがベターか。
スレッド考慮しなくても良いなら何も指定しない方が早い。
次は System.Threading.LazyInitializer
について調べてみる