view Christie/for.NET.md @ 134:e965a4b3e697 default tip

backup 2023-11-14
author autobackup
date Tue, 14 Nov 2023 00:10:04 +0900
parents 0bd2a99a349e
children
line wrap: on
line source

# ChristieのC#への書き換えログ

## メソッド等の置換一覧
java ConcurrentHashMap<> → C# ConcurrentDictionary<>  
java map<> → C# Dictionary<>  
java getClass() → C# GetType()  
java getGenericSuperclass() → C# type.BaseType 補足あり  
java ClassCastException → C# InvalidCastException  
java ByteBuffer → C# MemoryStream
```
java
T data = null;
Class<T> clazz = null;
byte[] messsagePack = null;
MessagePack packer = new MessagePack();
// write read
messagePack = packer.write(data); 
packer.read(messagePack, clazz);


C#
T data;
Type clazz = null;
byte[] messagePack = null;
// write read
messagePack = MessagePackSerializer.Serialize(data);
MessagePackSerializer.Deserialize<T>(messagePack);
``` 
java TreeMap&lt;&gt; → C# SortedDictionary&lt;&gt;  
java HashMap&lt;&gt; → C# Dictionary&lt;&gt;  
java Class clazz → C# Type clazz  
java LinkedBlockingQueue&lt;&gt; → C# ~~ConcurrentQueue&lt;&gt;~~  → BlockingCollection&lt;&gt;  
java socket.getInetAddress().getHostName() → C# Dns.GetHostEntry(((IPEndPoint) socket.RemoteEndPoint).Address.ToString()).HostName  
java clazz.getName() → C# `type.Name`
java socket.getInputStream().read() → C# socket.Receive([格納する配列]) (intの長さが返る) 
java ClassNotFoundException  → C# TypeLoadException 
java ArrayList&lt;E&gt; → C# List&lt;E&gt;


---

## MessagePackが使用されていたクラス
* MessagePackDataGear
* RemoteMessage



---
## 実装を飛ばしている物(仮置きしているもの)
IncomingTcpConnetion 送られてくるデータを格納する配列のサイズ  
PriorityThreadPoolExecutor ThreadPoolの優先度実装

---
## Tips
C# 
object → 全ての継承元クラス
Type → 型情報
T → ジェネリクス

---
javaのatomicintagerはc#に存在しない

intを読む, 代入するくらいは原始的が保証されているらしい
一度実装してみてダメなら
volatile修飾子をつける→読み書きがスレッドセーフになるが、コンパイラで最適化されない
https://ufcpp.net/study/csharp/misc_synchronize.html


intのインクリメントとかはこのメソッドを使ったほうがいいかも
https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=netcore-3.1

---


java
```public static <T> Class<T> [関数名] () { }```  
→ Class&lt;T&gt; は返り値の型  
→その前の&lt;T&gt;はジェネリスクメソッドの型を表す

C#
```public static Type [関数名]<T> () { }```   
→Typeは返り値の型  
→関数名の直後の&lt;T&gt;はジェネックメソッドの型を表す
    

java
int.class vs Intager.class  
javaは独自でそれぞれの型についてプリミティブ型とクラス型が用意されているらしい…
https://stackoverflow.com/questions/22470985/integer-class-vs-int-class/22471247


java側のdatagear/WrapperClassいらないかも...
もうちょい調べる

---
javaでは  
```T typeJava = null;```  
はできるがC#では初期化でT型にnullを代入できない  

T型の初期化は  
```T typeCs = default(T);```  
とする。(T)は省略可能  


---
java getGenericSuperclass() → type.BaseTypeについて
どちらも直接のスーパクラス、直接の継承元のTypeを返す


javaの場合
Object クラス、インタフェース、プリミティブ型、または void を表す場合、null が返され、配列の場合はClassが帰ってくる


C#の場合
直接の継承しているTypeを返す、もし現在のTypeがobjectかインターフェースならnullが返る

---
javaの場合  
ジェネリスククラスの宣言時にジェネリスクの型宣言は省略できる  
ex:``` Datagear dg;```


C#の場合  
ジェネリッククラス宣言時にジェネリックの型宣言は省略できない  
ex: ```Datagear<Type> dg; ```

---

~~MessagePackはjavaではread,writeにはジェネリックを使用できるが、
C#ではジェネリスクを使用することができない  
→ラッパーか何かを挟んで型判断してread,writeするしかない?~~
C#で関数名が全然異なっていた...  

javaリファレンス  
http://msgpack.org/javadoc/current/org/msgpack/MessagePack.html#read(byte[],%20java.lang.Class)  


C#README
https://github.com/neuecc/MessagePack-CSharp#quick-start  

---
C#のenumの扱いについて

C#のenumではstringは許容されていない
また、enum内でフィールド変数や関数を含めることはできないので、ヘルパークラスを実装してそちらを利用する必要がある

enum内でfor文などは使えないので、今回は別途関数を作成した
コンストラクタで使用するとか...?

---
java HashMapとC# Dictionaryの違いについて
https://stackoverflow.com/questions/1273139/c-sharp-java-hashmap-equivalent
null周りなど違いがあるので注意

---
~~C#のBlockingCollectionは既定ではConcurrentQueue、つまりFIFOになっているが、特に使う理由はないのでConcurrentQueueを最初から利用することに~~
→いやブロッキングどうするねん
→やっぱり使う
https://www.atmarkit.co.jp/ait/articles/1802/07/news019.html
→使用後にDisposeしないといけない
→無理...?
→もしかしたらずっとBlockingCollection利用してるかも
→Getするところでlengthが0になったもしくは
破棄をしていたらdisposeする

#### BlockingCollection使用箇所(Dispoes処理)
* Connection
* DataGears → fin
* WaitList → fin


---
C#だとsynchronized修飾子がないので
```
private object syncObject = new object();

public void Function(){
    lock (syncObject) {
                
    }
}
```
でロックをかける必要がある

---
javaだとジェネリッククラスを型として変数宣言する際にはジェネリックの型宣言は必要ないが、
c#では変数宣言する際に型宣言が必須なので、今回はとりあえずobject型で宣言している。

DataGearの宣言は基本的にDataGear&lt;object&gt;で

---
java側で出力されるsocket.getInetAddress().getHostName()
localhost:3333

~~これと同様の結果をC#でも欲しい感じ~~

javaはSocketクラスが割となんでもしてくれる感じがあるが、
C#はSocket, Dns, IPAdress, IPEndPointとかなり役割が分散されているので注意  

---
daemon/Connection

Close()について
socket.shutdownでSocketShutdown.Bothで本当にあっているか

---
java
socket.getChannel().write(buffer);について

javaのChannelではwrite(), read()などをByteBufferなどと一緒に使ってデータの送受信ができる。
Channelの開き方は、socketとは別にopenする必要があるので注意。

---
christleに導入されているMessagePackのバージョンは0.6以前のもの
そのため、シリアライズするクラスには@Messageが必要になる
https://github.com/msgpack/msgpack-java/wiki/QuickStart-for-msgpack-java-0.6.x-(obsolete)

java版は0.7.xから仕様がかなり変わっているため注意が必要  



C#版のMassagePackには日本人が作成したものを利用している(Unityとかでもサポートされているらしい)
https://github.com/neuecc/MessagePack-CSharp#quick-start


---
javaとC#のenumの仕様はかなり異なっており
C#ではenumにメソッドを生やすことができない  

~~最初はヘルパークラスを実装することで対応しようとしたが、挙動的にenum各要素を初期化する必要があるとわかったため、独自にenumの挙動をするクラスを作成した~~

https://qiita.com/lilacs/items/167a73fbbfedf83eb51a
https://bleis-tift.hatenablog.com/entry/20080808/1218133517

必要なのはenumをintにする変換なので、C#ではenumをintにcastできるので廃止

---
protected internalについて

---
LinkedBlockingQueueとConcurrentQueueの特徴について

* LinkedBlockingQueue
    * FIFO
    * boolean contains(Object o): 要素の確認
    * peek(): 先頭取得、削除しない
    * poll(): 先頭取得、削除
    * put(): 末尾に追加 完了するまでブロック
    * add(): 末尾に追加 失敗時例外
        * put, addの違いについては:https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/BlockingQueue.html#add-E-

* ConcurrentQueue
    * FIFO
    * スレッドセーフ
    * Enqueue(): 末尾に追加
    * 

---
Socketはaccept()するとその返り値にacceptされたsocketが返る  
よってそれを変数に入れて利用する


---
javaのThreadはThreadを継承して作成をする。  
Threadの名前をつける必要あり  


c#は
`Task task = Task.Run(() => MethodThread());
task.Run();`
(名前をつける必要なし)

---
IncommingTcpConnectionなどのスレッドはAcceptThreadで一括でTask.Runする

---
IncomingTcpConnetion  

送られてくるデータ長がわからないので
とりあえず4096と置いている

---
TCPで送受信するデータは、Remotemessage(Command), length, dataの順で入っている  

PutCommand
Command
IncomingTcpConnection
を参照

---
javaではserverSocketクラスがあり、listenerはこれを使えばいいが、c# 側にはない。  

ここで注意するのが、javaではacceptでlistenを開始するが、C#ではListenでlistenを開始することに注意


---
優先度付きThreadPoolについて  
javaのほうでは実装されているが、現状処理が複雑なため一旦実装を飛ばす  
優先度が実装されている理由についてはheartbeatを実装したかったと考えられる  

Taskは内部でThreadPoolを作成しているらしい
https://oita.oika.me/2016/02/18/task-and-threadpool/  

優先度をつけるならThreadPoolはTaskを利用できないかも

---
Task.RunとTask.Factory.Startnewについて

無限ループさせるような、すぐには終了しないTaskについては
LongRunオプションをつける必要がある。

これは、Task.Runは裏でThreadPoolを作るが、この数がTask.Runの場合規定数(通常だと16(cpuに依存))に制限されており、無限ループのTaskも個の規定数にカウントされてしまうため  
https://oita.oika.me/2016/02/18/task-and-threadpool/  

それを避けるためにStartnewでTaskを作成する  

https://qiita.com/chocolamint/items/3e2e4951ea0fa2ccd19e

---
C#のTaskでのThreadPoolについて  

https://stackoverflow.com/questions/35734051/c-sharp-task-thread-pool-running-100-tasks-across-only-10-threads  

---
lockのwaitとnotifyについて  
Javaでは排他制御として`synchronized(lock)`(lockはobject型)を使用することで排他制御ができる。  
解除にはlock.notifyなどを使う
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#notify()  

C#ではMoniterクラスの中にwaitやpulse関数があり、同じように使えるっぽい
https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor.pulse?view=net-5.0  

```java
Object lock = new Object;
synchronized(lock) {
	lock.notify();    // lockの解除
}
```

```c#
objecy lockObj = new object;
lock(lockObj) {
	Moniter.Pulse(lock);
}
```
---
csprojectのStartupObjectでnamespaceを含めた書き方は  

`<StartupObject>Christie_net.AttributeCheck</StartupObject>`  
のようにドットでつなぐ 

---
フィールド変数などにつけたattributeは次のように取得できる  

```c#
public class AttributeCheck {
    [Take] private int num = 0;
    [Peek] public string name = "riono";
    [PeekFrom("name")] protected string nextName = "local";
    
    
    private static void Main(string[] args) {
        AttributeCheck attributeCheck = new AttributeCheck();

        foreach (var field in attributeCheck.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic 
                                                                           | BindingFlags.DeclaredOnly | BindingFlags.Instance)) {
            foreach (var attribute in field.GetCustomAttributes(false)) {
                Console.WriteLine(attribute);   
            }
        }
    }
	
//  Result
//  Christie_net.annotation.Take
//  Christie_net.annotation.Peek
//  Christie_net.annotation.PeekFrom

```
BindingFlagsについては下記を参照  
https://dobon.net/vb/dotnet/programing/typegetmembers.html  


---
## TODO
* annotation → fin
* daemon
    * connection → fin
    * ChristieDaemon → fin
    * AcceptThread → fin
    * IncomingTcpConnection → fin
    * OutboundTcpConnection → fin
    * ThreadPoolExecutors 実装
    * Config → toporogyManager作成時に必要?
    	* log4netかNlogのどちらかを使う
* codegear
    * CodeGear → fin
    * InputDataGear → fin
    * CodeGearManager → fin
    * CodeGearExecutor → fin
* datagear
    * command
        * Command → fin
        * CommandType → fin
        * CommandBuilder → fin
        * TakeCommand → fin
        * その他のcommand → fin
    * dg → fin
    * DataGearManager → fin
    * DataGears → fin
    * WaitList → fin
    * LocalDataGearManager → fin
    * RemoteDataGearManager → fin