2
|
1 # ChristieのC#への書き換えログ
|
|
2
|
|
3 ## メソッド等の置換一覧
|
|
4 java ConcurrentHashMap<> → C# ConcurrentDictionary<>
|
|
5 java map<> → C# Dictionary<>
|
|
6 java getClass() → C# GetType()
|
|
7 java getGenericSuperclass() → C# type.BaseType 補足あり
|
|
8 java ClassCastException → C# InvalidCastException
|
|
9 java ByteBuffer → C# MemoryStream
|
|
10 ```
|
|
11 java
|
|
12 T data = null;
|
|
13 Class<T> clazz = null;
|
|
14 byte[] messsagePack = null;
|
|
15 MessagePack packer = new MessagePack();
|
|
16 // write read
|
|
17 messagePack = packer.write(data);
|
|
18 packer.read(messagePack, clazz);
|
|
19
|
0
|
20
|
2
|
21 C#
|
|
22 T data;
|
|
23 Type clazz = null;
|
|
24 byte[] messagePack = null;
|
|
25 // write read
|
|
26 messagePack = MessagePackSerializer.Serialize(data);
|
|
27 MessagePackSerializer.Deserialize<T>(messagePack);
|
|
28 ```
|
|
29 java TreeMap<> → C# SortedDictionary<>
|
|
30 java HashMap<> → C# Dictionary<>
|
|
31 java Class clazz → C# Type clazz
|
15
|
32 java LinkedBlockingQueue<> → C# ~~ConcurrentQueue<>~~ → BlockingCollection<>
|
2
|
33 java socket.getInetAddress().getHostName() → C# Dns.GetHostEntry(((IPEndPoint) socket.RemoteEndPoint).Address.ToString()).HostName
|
|
34 java clazz.getName() → C# `type.Name`
|
|
35 java socket.getInputStream().read() → C# socket.Receive([格納する配列]) (intの長さが返る)
|
|
36 java ClassNotFoundException → C# TypeLoadException
|
29
|
37 java ArrayList<E> → C# List<E>
|
|
38
|
0
|
39
|
2
|
40 ---
|
|
41
|
|
42 ## MessagePackが使用されていたクラス
|
|
43 * MessagePackDataGear
|
|
44 * RemoteMessage
|
|
45
|
|
46
|
|
47
|
|
48 ---
|
14
|
49 ## 実装を飛ばしている物(仮置きしているもの)
|
|
50 IncomingTcpConnetion 送られてくるデータを格納する配列のサイズ
|
|
51 PriorityThreadPoolExecutor ThreadPoolの優先度実装
|
|
52
|
|
53 ---
|
2
|
54 ## Tips
|
|
55 C#
|
|
56 object → 全ての継承元クラス
|
|
57 Type → 型情報
|
|
58 T → ジェネリクス
|
|
59
|
|
60 ---
|
|
61 javaのatomicintagerはc#に存在しない
|
0
|
62
|
|
63 intを読む, 代入するくらいは原始的が保証されているらしい
|
|
64 一度実装してみてダメなら
|
|
65 volatile修飾子をつける→読み書きがスレッドセーフになるが、コンパイラで最適化されない
|
|
66 https://ufcpp.net/study/csharp/misc_synchronize.html
|
|
67
|
|
68
|
|
69 intのインクリメントとかはこのメソッドを使ったほうがいいかも
|
|
70 https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=netcore-3.1
|
|
71
|
2
|
72 ---
|
0
|
73
|
|
74
|
|
75 java
|
2
|
76 ```public static <T> Class<T> [関数名] () { }```
|
|
77 → Class<T> は返り値の型
|
|
78 →その前の<T>はジェネリスクメソッドの型を表す
|
|
79
|
|
80 C#
|
|
81 ```public static Type [関数名]<T> () { }```
|
|
82 →Typeは返り値の型
|
|
83 →関数名の直後の<T>はジェネックメソッドの型を表す
|
|
84
|
|
85
|
|
86 java
|
|
87 int.class vs Intager.class
|
|
88 javaは独自でそれぞれの型についてプリミティブ型とクラス型が用意されているらしい…
|
|
89 https://stackoverflow.com/questions/22470985/integer-class-vs-int-class/22471247
|
|
90
|
|
91
|
|
92 java側のdatagear/WrapperClassいらないかも...
|
|
93 もうちょい調べる
|
|
94
|
|
95 ---
|
|
96 javaでは
|
|
97 ```T typeJava = null;```
|
|
98 はできるがC#では初期化でT型にnullを代入できない
|
|
99
|
|
100 T型の初期化は
|
|
101 ```T typeCs = default(T);```
|
|
102 とする。(T)は省略可能
|
|
103
|
|
104
|
|
105 ---
|
|
106 java getGenericSuperclass() → type.BaseTypeについて
|
|
107 どちらも直接のスーパクラス、直接の継承元のTypeを返す
|
|
108
|
|
109
|
|
110 javaの場合
|
|
111 Object クラス、インタフェース、プリミティブ型、または void を表す場合、null が返され、配列の場合はClassが帰ってくる
|
|
112
|
|
113
|
|
114 C#の場合
|
|
115 直接の継承しているTypeを返す、もし現在のTypeがobjectかインターフェースならnullが返る
|
|
116
|
|
117 ---
|
|
118 javaの場合
|
|
119 ジェネリスククラスの宣言時にジェネリスクの型宣言は省略できる
|
|
120 ex:``` Datagear dg;```
|
|
121
|
|
122
|
|
123 C#の場合
|
|
124 ジェネリッククラス宣言時にジェネリックの型宣言は省略できない
|
|
125 ex: ```Datagear<Type> dg; ```
|
|
126
|
|
127 ---
|
|
128
|
|
129 ~~MessagePackはjavaではread,writeにはジェネリックを使用できるが、
|
|
130 C#ではジェネリスクを使用することができない
|
|
131 →ラッパーか何かを挟んで型判断してread,writeするしかない?~~
|
|
132 C#で関数名が全然異なっていた...
|
|
133
|
|
134 javaリファレンス
|
|
135 http://msgpack.org/javadoc/current/org/msgpack/MessagePack.html#read(byte[],%20java.lang.Class)
|
|
136
|
|
137
|
|
138 C#README
|
|
139 https://github.com/neuecc/MessagePack-CSharp#quick-start
|
|
140
|
|
141 ---
|
|
142 C#のenumの扱いについて
|
|
143
|
|
144 C#のenumではstringは許容されていない
|
|
145 また、enum内でフィールド変数や関数を含めることはできないので、ヘルパークラスを実装してそちらを利用する必要がある
|
|
146
|
|
147 enum内でfor文などは使えないので、今回は別途関数を作成した
|
|
148 コンストラクタで使用するとか...?
|
|
149
|
|
150 ---
|
|
151 java HashMapとC# Dictionaryの違いについて
|
|
152 https://stackoverflow.com/questions/1273139/c-sharp-java-hashmap-equivalent
|
|
153 null周りなど違いがあるので注意
|
|
154
|
|
155 ---
|
|
156 ~~C#のBlockingCollectionは既定ではConcurrentQueue、つまりFIFOになっているが、特に使う理由はないのでConcurrentQueueを最初から利用することに~~
|
|
157 →いやブロッキングどうするねん
|
|
158 →やっぱり使う
|
|
159 https://www.atmarkit.co.jp/ait/articles/1802/07/news019.html
|
|
160 →使用後にDisposeしないといけない
|
|
161 →無理...?
|
|
162 →もしかしたらずっとBlockingCollection利用してるかも
|
|
163 →Getするところでlengthが0になったもしくは
|
|
164 破棄をしていたらdisposeする
|
|
165
|
15
|
166 #### BlockingCollection使用箇所(Dispoes処理)
|
2
|
167 * Connection
|
|
168 * DataGears → fin
|
|
169 * WaitList → fin
|
0
|
170
|
|
171
|
2
|
172 ---
|
|
173 C#だとsynchronized修飾子がないので
|
|
174 ```
|
|
175 private object syncObject = new object();
|
|
176
|
|
177 public void Function(){
|
|
178 lock (syncObject) {
|
|
179
|
|
180 }
|
|
181 }
|
|
182 ```
|
|
183 でロックをかける必要がある
|
|
184
|
|
185 ---
|
|
186 javaだとジェネリッククラスを型として変数宣言する際にはジェネリックの型宣言は必要ないが、
|
|
187 c#では変数宣言する際に型宣言が必須なので、今回はとりあえずobject型で宣言している。
|
|
188
|
|
189 DataGearの宣言は基本的にDataGear<object>で
|
|
190
|
|
191 ---
|
|
192 java側で出力されるsocket.getInetAddress().getHostName()
|
|
193 localhost:3333
|
|
194
|
|
195 ~~これと同様の結果をC#でも欲しい感じ~~
|
|
196
|
|
197 javaはSocketクラスが割となんでもしてくれる感じがあるが、
|
|
198 C#はSocket, Dns, IPAdress, IPEndPointとかなり役割が分散されているので注意
|
|
199
|
|
200 ---
|
|
201 daemon/Connection
|
|
202
|
|
203 Close()について
|
|
204 socket.shutdownでSocketShutdown.Bothで本当にあっているか
|
|
205
|
|
206 ---
|
0
|
207 java
|
2
|
208 socket.getChannel().write(buffer);について
|
|
209
|
|
210 javaのChannelではwrite(), read()などをByteBufferなどと一緒に使ってデータの送受信ができる。
|
|
211 Channelの開き方は、socketとは別にopenする必要があるので注意。
|
|
212
|
|
213 ---
|
|
214 christleに導入されているMessagePackのバージョンは0.6以前のもの
|
|
215 そのため、シリアライズするクラスには@Messageが必要になる
|
|
216 https://github.com/msgpack/msgpack-java/wiki/QuickStart-for-msgpack-java-0.6.x-(obsolete)
|
|
217
|
|
218 java版は0.7.xから仕様がかなり変わっているため注意が必要
|
|
219
|
|
220
|
|
221
|
|
222 C#版のMassagePackには日本人が作成したものを利用している(Unityとかでもサポートされているらしい)
|
|
223 https://github.com/neuecc/MessagePack-CSharp#quick-start
|
|
224
|
|
225
|
|
226 ---
|
|
227 javaとC#のenumの仕様はかなり異なっており
|
|
228 C#ではenumにメソッドを生やすことができない
|
|
229
|
|
230 ~~最初はヘルパークラスを実装することで対応しようとしたが、挙動的にenum各要素を初期化する必要があるとわかったため、独自にenumの挙動をするクラスを作成した~~
|
|
231
|
|
232 https://qiita.com/lilacs/items/167a73fbbfedf83eb51a
|
|
233 https://bleis-tift.hatenablog.com/entry/20080808/1218133517
|
|
234
|
|
235 必要なのはenumをintにする変換なので、C#ではenumをintにcastできるので廃止
|
|
236
|
|
237 ---
|
|
238 protected internalについて
|
|
239
|
|
240 ---
|
|
241 LinkedBlockingQueueとConcurrentQueueの特徴について
|
|
242
|
|
243 * LinkedBlockingQueue
|
|
244 * FIFO
|
|
245 * boolean contains(Object o): 要素の確認
|
|
246 * peek(): 先頭取得、削除しない
|
|
247 * poll(): 先頭取得、削除
|
|
248 * put(): 末尾に追加 完了するまでブロック
|
|
249 * add(): 末尾に追加 失敗時例外
|
|
250 * put, addの違いについては:https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/BlockingQueue.html#add-E-
|
|
251
|
|
252 * ConcurrentQueue
|
|
253 * FIFO
|
|
254 * スレッドセーフ
|
|
255 * Enqueue(): 末尾に追加
|
|
256 *
|
|
257
|
|
258 ---
|
|
259 Socketはaccept()するとその返り値にacceptされたsocketが返る
|
|
260 よってそれを変数に入れて利用する
|
|
261
|
|
262
|
|
263 ---
|
5
|
264 javaのThreadはThreadを継承して作成をする。
|
|
265 Threadの名前をつける必要あり
|
2
|
266
|
|
267
|
|
268 c#は
|
|
269 `Task task = Task.Run(() => MethodThread());
|
|
270 task.Run();`
|
5
|
271 (名前をつける必要なし)
|
2
|
272
|
|
273 ---
|
|
274 IncommingTcpConnectionなどのスレッドはAcceptThreadで一括でTask.Runする
|
|
275
|
|
276 ---
|
|
277 IncomingTcpConnetion
|
|
278
|
|
279 送られてくるデータ長がわからないので
|
|
280 とりあえず4096と置いている
|
|
281
|
|
282 ---
|
|
283 TCPで送受信するデータは、Remotemessage(Command), length, dataの順で入っている
|
|
284
|
|
285 PutCommand
|
|
286 Command
|
|
287 IncomingTcpConnection
|
|
288 を参照
|
|
289
|
5
|
290 ---
|
|
291 javaではserverSocketクラスがあり、listenerはこれを使えばいいが、c# 側にはない。
|
|
292
|
23
|
293 ここで注意するのが、javaではacceptでlistenを開始するが、C#ではListenでlistenを開始することに注意
|
2
|
294
|
|
295
|
|
296 ---
|
14
|
297 優先度付きThreadPoolについて
|
|
298 javaのほうでは実装されているが、現状処理が複雑なため一旦実装を飛ばす
|
|
299 優先度が実装されている理由についてはheartbeatを実装したかったと考えられる
|
|
300
|
|
301 Taskは内部でThreadPoolを作成しているらしい
|
|
302 https://oita.oika.me/2016/02/18/task-and-threadpool/
|
|
303
|
|
304 優先度をつけるならThreadPoolはTaskを利用できないかも
|
|
305
|
|
306 ---
|
15
|
307 Task.RunとTask.Factory.Startnewについて
|
|
308
|
|
309 無限ループさせるような、すぐには終了しないTaskについては
|
|
310 LongRunオプションをつける必要がある。
|
|
311
|
|
312 これは、Task.Runは裏でThreadPoolを作るが、この数がTask.Runの場合規定数(通常だと16(cpuに依存))に制限されており、無限ループのTaskも個の規定数にカウントされてしまうため
|
|
313 https://oita.oika.me/2016/02/18/task-and-threadpool/
|
|
314
|
|
315 それを避けるためにStartnewでTaskを作成する
|
|
316
|
|
317 https://qiita.com/chocolamint/items/3e2e4951ea0fa2ccd19e
|
|
318
|
|
319 ---
|
|
320 C#のTaskでのThreadPoolについて
|
|
321
|
|
322 https://stackoverflow.com/questions/35734051/c-sharp-task-thread-pool-running-100-tasks-across-only-10-threads
|
|
323
|
|
324 ---
|
27
|
325 lockのwaitとnotifyについて
|
|
326 Javaでは排他制御として`synchronized(lock)`(lockはobject型)を使用することで排他制御ができる。
|
|
327 解除にはlock.notifyなどを使う
|
|
328 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#notify()
|
|
329
|
|
330 C#ではMoniterクラスの中にwaitやpulse関数があり、同じように使えるっぽい
|
|
331 https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor.pulse?view=net-5.0
|
|
332
|
|
333 ```java
|
|
334 Object lock = new Object;
|
|
335 synchronized(lock) {
|
|
336 lock.notify(); // lockの解除
|
|
337 }
|
|
338 ```
|
|
339
|
|
340 ```c#
|
|
341 objecy lockObj = new object;
|
|
342 lock(lockObj) {
|
|
343 Moniter.Pulse(lock);
|
|
344 }
|
|
345 ```
|
29
|
346 ---
|
|
347 csprojectのStartupObjectでnamespaceを含めた書き方は
|
|
348
|
|
349 `<StartupObject>Christie_net.AttributeCheck</StartupObject>`
|
|
350 のようにドットでつなぐ
|
|
351
|
|
352 ---
|
|
353 フィールド変数などにつけたattributeは次のように取得できる
|
|
354
|
|
355 ```c#
|
|
356 public class AttributeCheck {
|
|
357 [Take] private int num = 0;
|
|
358 [Peek] public string name = "riono";
|
|
359 [PeekFrom("name")] protected string nextName = "local";
|
|
360
|
|
361
|
|
362 private static void Main(string[] args) {
|
|
363 AttributeCheck attributeCheck = new AttributeCheck();
|
|
364
|
|
365 foreach (var field in attributeCheck.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic
|
|
366 | BindingFlags.DeclaredOnly | BindingFlags.Instance)) {
|
|
367 foreach (var attribute in field.GetCustomAttributes(false)) {
|
|
368 Console.WriteLine(attribute);
|
|
369 }
|
|
370 }
|
|
371 }
|
|
372
|
|
373 // Result
|
|
374 // Christie_net.annotation.Take
|
|
375 // Christie_net.annotation.Peek
|
|
376 // Christie_net.annotation.PeekFrom
|
|
377
|
|
378 ```
|
|
379 BindingFlagsについては下記を参照
|
|
380 https://dobon.net/vb/dotnet/programing/typegetmembers.html
|
|
381
|
27
|
382
|
|
383 ---
|
2
|
384 ## TODO
|
|
385 * annotation → fin
|
|
386 * daemon
|
29
|
387 * connection → fin
|
5
|
388 * ChristieDaemon → fin
|
29
|
389 * AcceptThread → fin
|
|
390 * IncomingTcpConnection → fin
|
2
|
391 * OutboundTcpConnection → fin
|
27
|
392 * ThreadPoolExecutors 実装
|
29
|
393 * Config → toporogyManager作成時に必要?
|
|
394 * log4netかNlogのどちらかを使う
|
2
|
395 * codegear
|
29
|
396 * CodeGear → fin
|
|
397 * InputDataGear → fin
|
|
398 * CodeGearManager → fin
|
|
399 * CodeGearExecutor → fin
|
2
|
400 * datagear
|
|
401 * command
|
|
402 * Command → fin
|
|
403 * CommandType → fin
|
|
404 * CommandBuilder → fin
|
29
|
405 * TakeCommand → fin
|
2
|
406 * その他のcommand → fin
|
|
407 * dg → fin
|
|
408 * DataGearManager → fin
|
|
409 * DataGears → fin
|
|
410 * WaitList → fin
|
|
411 * LocalDataGearManager → fin
|
27
|
412 * RemoteDataGearManager → fin
|
2
|
413
|
|
414
|
|
415
|
|
416
|