# 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 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(messagePack); ``` java TreeMap<> → C# SortedDictionary<> java HashMap<> → C# Dictionary<> java Class clazz → C# Type clazz java LinkedBlockingQueue<> → C# ~~ConcurrentQueue<>~~ → BlockingCollection<> 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<E> → C# List<E> --- ## 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 Class [関数名] () { }``` → Class<T> は返り値の型 →その前の<T>はジェネリスクメソッドの型を表す C# ```public static Type [関数名] () { }``` →Typeは返り値の型 →関数名の直後の<T>はジェネックメソッドの型を表す 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 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<object>で --- 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を含めた書き方は `Christie_net.AttributeCheck` のようにドットでつなぐ  --- フィールド変数などにつけた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