コマンドとイベントの実行制御
ExtensionPointsではコマンドやイベントの実行中にAPIを操作した場合に、多重でイベントが発生しないように抑制しています。これによってコマンド処理中にイベントが想定しない場面で発火して処理しパフォーマンス低下や機能的なバグにつながってしまうことを避けています。なお、ExtensionPointsライブラリを用いない標準エクステンション開発では、APIでモデルを編集してもモデルの編集イベントが発火します。
例えば次のようなケースを想定します。 モデルを一括で作成するような機能を開発したとします。
public class AddUseCasesCommand : CommandHandlerBase
{
protected override void OnExecute(ICommandContext c, ICommandParams p)
{
for ( var i=0;i<10;i++)
{
var useCaseModel = CurrentModel.AddNewModel("UseCases", "UseCase");
// フィールドを設定します
useCaseModel.SetField("Name", $"MyUseCase {i}");
useCaseModel.SetField("Description", "MyUseCase");
useCaseModel.SetField("SomeField", "xxx");
}
}
}
また、ユーザがモデルを編集した場合に、何らかのデータの補正を行うような実装を行うため、モデルのフィールド編集時のイベントハンドラを登録したとします。 モデルを作成するタイミングではモデルの変更イベントは処理させたくないというケースがあります。
public class UseCaseModelFieldChangedEvent : ModelsFieldChangedEventHandlerBase
{
protected override void OnHandle(IEventContext c, ModelFieldChangedEventParams p)
{
// ...
}
}
この場合、ExtensionPointsはコマンドのOnExecute
、イベントのOnHandle
メソッド内でモデルを変更しても新たなイベントは発火しないように抑制しています。コマンドやイベントで共通的な初期化を行う場合は専用のクラスを定義してそこに振る舞いを集約させるなどをして工夫をして下さい。例えば次のようにモデルの振る舞いと属性をクラスとして定義するのも良いアプローチです。
モデルのクラス
public class UseCaseModel
{
private IModel m_Model;
public UseCaseModel(IModel m)
{
m_Model = m;
}
public void Initialize(int i=0)
{
m_Model.SetField("Name", $"MyUseCase {i}");
m_Model.SetField("Description", "MyUseCase");
m_Model.SetField("SomeField", "xxx");
}
public void SomeMethod()
{
m_Model.SetField(...);
}
}
コマンドハンドラ
public class AddUseCasesCommand : CommandHandlerBase
{
protected override void OnExecute(ICommandContext c, ICommandParams p)
{
for ( var i=0;i<10;i++)
{
var m = CurrentModel.AddNewModel("UseCases", "UseCase");
var useCaseModel = new UseCaseModel(m);
// フィールドを設定します
useCaseModel.Initialize(i);
}
}
}
重要
なお、この抑制の仕組みは同一のエクステンション内部でのみ機能します。エクステンションを横断してイベントの抑制はしませんのでご注意下さい。