質問するログイン新規登録

質問編集履歴

2

コードにコメントを追加

2021/09/14 12:28

投稿

tonica
tonica

スコア0

title CHANGED
File without changes
body CHANGED
@@ -106,7 +106,7 @@
106
106
  public async void ProcUseCase()
107
107
  {
108
108
  if (entity == null) return;
109
- await DomainService.HeavyWork(entity);
109
+ await DomainService.HeavyWork(entity); // 他のUseCaseが呼ばれるとエラー
110
110
  DataUpdated?.Invoke(this, EventArgs.Empty);
111
111
  }
112
112
 

1

コードの例の追加

2021/09/14 12:28

投稿

tonica
tonica

スコア0

title CHANGED
File without changes
body CHANGED
@@ -18,4 +18,150 @@
18
18
 
19
19
  こういう問題は重い処理を行うアプリでは頻出すると思うので、同期処理と非同期な重い処理を分けて、
20
20
  重い処理(タスク)を管理する仕組みがあるのではないかと思うのですが、
21
- そういった仕組みを作って解決するべきでしょうか。
21
+ そういった仕組みを作って解決するべきでしょうか。
22
+
23
+ ####### 追記
24
+ コードの例です。WPFなのでViewModelでBindingを行っていますが、質問の部分はInteractorの各UseCaseです。
25
+ 例のためTask.Delayを使っていますが、ProcUseCaseを呼び出した直後にLoadUseCaseを呼び出すとエラーになります。
26
+ 各UseCaseを排他的に呼び出す処理をInteractorに持たせるか、もしくは非同期な処理を管理するクラスを作るか、
27
+ このあたりの設計が分からず悩んでいます。
28
+ 書いていて思ったのですが後者のほうが簡単かもしれません…
29
+
30
+ ```C#
31
+ using System;
32
+ using System.Threading.Tasks;
33
+ using System.Windows;
34
+
35
+ namespace WpfArchTestApp
36
+ {
37
+ internal class Entity
38
+ {
39
+ public string Data
40
+ {
41
+ get { return disposed ? throw new ObjectDisposedException("Entity") : data; }
42
+ set { data = value; }
43
+ }
44
+ private string data;
45
+ private bool disposed = false;
46
+ public void Dispose() { disposed = true; }
47
+ }
48
+
49
+ internal class Repository
50
+ {
51
+ public async Task<Entity> Load()
52
+ {
53
+ await Task.Delay(1000);
54
+ return new Entity { Data = "TestStringData" };
55
+ }
56
+
57
+ public async Task Save(Entity _)
58
+ {
59
+ await Task.Delay(1000);
60
+ }
61
+ }
62
+
63
+ internal class DomainService
64
+ {
65
+ public static async Task HeavyWork(Entity entity)
66
+ {
67
+ for (int i = 0; i < entity.Data.Length; ++i)
68
+ {
69
+ for (int j = 0; j < entity.Data.Length; ++j)
70
+ {
71
+ if (entity.Data[i] >= entity.Data[j]) continue;
72
+ char[] charArray = entity.Data.ToCharArray();
73
+ charArray[j] = entity.Data[i];
74
+ charArray[i] = entity.Data[j];
75
+ entity.Data = new string(charArray);
76
+ await Task.Delay(20);
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ internal class Interactor
83
+ {
84
+ public event EventHandler DataUpdated;
85
+ public string Data { get { return entity == null ? "" : entity.Data; } }
86
+
87
+ private readonly Repository repository;
88
+ private Entity entity;
89
+
90
+ public Interactor(Repository repository)
91
+ {
92
+ this.repository = repository;
93
+ }
94
+
95
+ public async void LoadUseCase()
96
+ {
97
+ if (entity != null)
98
+ {
99
+ entity.Dispose();
100
+ entity = null;
101
+ }
102
+ entity = await repository.Load();
103
+ DataUpdated?.Invoke(this, EventArgs.Empty);
104
+ }
105
+
106
+ public async void ProcUseCase()
107
+ {
108
+ if (entity == null) return;
109
+ await DomainService.HeavyWork(entity);
110
+ DataUpdated?.Invoke(this, EventArgs.Empty);
111
+ }
112
+
113
+ public async void SaveUseCase()
114
+ {
115
+ if (entity == null) return;
116
+ await repository.Save(entity);
117
+ entity.Dispose();
118
+ entity = null;
119
+ DataUpdated?.Invoke(this, EventArgs.Empty);
120
+ }
121
+ }
122
+
123
+ internal class MainWindowViewModel : VMCommon.ViewModelBase
124
+ {
125
+ public VMCommon.DelegateCommand LoadCommand { get; }
126
+ public VMCommon.DelegateCommand ProcCommand { get; }
127
+ public VMCommon.DelegateCommand SaveCommand { get; }
128
+ public string Data
129
+ {
130
+ get { return data; }
131
+ private set
132
+ {
133
+ if (data == value) return;
134
+ data = value;
135
+ RaiseProeprtyChanged();
136
+ }
137
+ }
138
+
139
+ private readonly Interactor interactor;
140
+ private string data;
141
+
142
+ public MainWindowViewModel()
143
+ {
144
+ Repository repository = new Repository();
145
+ interactor = new Interactor(repository);
146
+ LoadCommand = new VMCommon.DelegateCommand(_ => interactor.LoadUseCase());
147
+ ProcCommand = new VMCommon.DelegateCommand(_ => interactor.ProcUseCase());
148
+ SaveCommand = new VMCommon.DelegateCommand(_ => interactor.SaveUseCase());
149
+ interactor.DataUpdated += Interactor_DataUpdated;
150
+ }
151
+
152
+ private void Interactor_DataUpdated(object sender, EventArgs e)
153
+ {
154
+ Data = interactor.Data;
155
+ }
156
+ }
157
+
158
+ public partial class MainWindow : Window
159
+ {
160
+ public MainWindow()
161
+ {
162
+ InitializeComponent();
163
+ DataContext = new MainWindowViewModel();
164
+ }
165
+ }
166
+ }
167
+ ```