Open6

IDisposable活用法

MakihiroMakihiro

Factoryパターン + IDisposableは便利
操作の終了をDispose()だけで出来ちまうんだ

public static IDisposable BindTo (this IPool pool,IReadOnlyTimer timer,int keep) {
	return new TimerBinding(pool,timer,keep);
}

class TimerBinding : IDisposable {

	readonly IReadOnlyTimer m_Timer;
	readonly IPool m_Pool;
	readonly int m_Keep;
	bool m_IsDisposed;

	public TimerBinding (IPool pool,IReadOnlyTimer timer,int keep) {
		m_Pool = pool;
		m_Timer = timer;
		m_Keep = keep;

		m_Timer.OnElapsed += OnElapsed;
	}

	public void Dispose () {
		if (m_IsDisposed) {
			return;
		}
		m_IsDisposed = true;
		m_Timer.OnElapsed -= OnElapsed;
	}

	void OnElapsed () {
		m_Pool.ReleaseInstances(m_Keep > m_Pool.Capacity ? m_Pool.Capacity : m_Keep);
	}
}

https://github.com/mackysoft/XPool/blob/main/Assets/MackySoft/MackySoft.XPool/Runtime/PoolExtensions.cs

MakihiroMakihiro

UniRxにもあるけど、IDisposableを結合する関数があると便利

public static IDisposable Combine (IDisposable disposable1,IDisposable disposable2) {
	return new Binary(disposable1,disposable2);
}

class Binary : IDisposable {

	readonly IDisposable m_Disposable1;
	readonly IDisposable m_Disposable2;

	public Binary (IDisposable disposable1,IDisposable disposable2) {
		m_Disposable1 = disposable1;
		m_Disposable2 = disposable2;
	}

	public void Dispose () {
		m_Disposable1.Dispose();
		m_Disposable2.Dispose();
	}
}
MakihiroMakihiro

タプルで結合出来たら最高じゃね!?と思ったけど許されていなかった

public static IDisposable Combine (this (IDisposable disposable1,IDisposable disposable2) source) {
	return new Binary(source.disposable1,source.disposable2);
}

MakihiroMakihiro

オブジェクトプールでの借用トークンとしてIDisposableを返して、outでインスタンスを手法。

public static RentInstance<T> RentTemporary<T> (this IPool<T> pool,out T instance) {
	if (pool == null) {
		throw Error.ArgumentNullException(nameof(pool));
	}
	instance = pool.Rent();
	return new RentInstance<T>(pool,instance);
}

public struct RentInstance<T> : IDisposable {

	readonly T m_Instance;
	readonly IPool<T> m_Pool;

	internal RentInstance (IPool<T> pool,T instance) {
		m_Pool = pool;
		m_Instance = instance;
	}

	public void Dispose () => m_Pool.Return(m_Instance);

}

usingステートメントとの合わせ技で簡単に使えて最高

using (pool.RentTemporary(out T instance)) {
	// このブロック内だけ、プールからインスタンスを借りる
}
MakihiroMakihiro

最近よくやるやつ

// スクリーンをブロック(内部的に参照カウントを増やす)
using (m_ScreenBlocker.Block()) {
    // 何かしらの待機処理
}
MakihiroMakihiro

Navigathenaの処理カウントでやったやつ

using var _ = m_ProcessCounter.Increment();

関数のスコープ内で使うことで、スコープを抜けたら勝手に解放される。これによって、usingブロックによるネストを発生させなくても良くなる。ただし、変数の定義の部分は完全に無駄感ある