20190927のC#に関する記事は5件です。

【Unity】PUN2でRpcTarget.AllBufferedとかOthersBufferedが仕事してない時に見るメモ

はじめに

ここへたどり着いたということは、
PhotonのRpcTarget.AllとRpcTarget.AllBufferedの違いは分かっているということでしょう。
分かっていない方は以下のブログ推奨です(PUN2の記事ではないですが、内容的には同じです)。
【Unity】僕もPhotonを使いたい #08 RPC() PhotonTargets編

RpcTarget.○○Bufferedを使うと、後からルームに入室した人にもデータを送信してくれます。
が、この情報だけを見てドツボにハマってしまったのでメモ。

Sceneをまたぐときはちょっと特別

単刀直入に言うとここの内容です。
【Unity】僕もPhotonを使いたい #13 isMessageQueueRunning
私はここを見る前に、よっしゃRPC使ったるでー!と先走ってしまい、
いや、Buffered動かないやんけ・・・と、同じ目に遭遇してしまった・・・。

上記のリンク先と少しだけ違うのが、PUN2では

PhotonNetwork.IsMessageQueueRunning

IsのIが大文字になってます。

最後に

内容の無い記事になっていますが、
載せたリンク先はPUN2のワードで検索をかけると出会えない可能性があるので、
PUN2を使っている人が検索をかけそうなワードを散りばめているつもりです。
というのは建前で、忘れたころの自分が検索かけそうなワードを散りばめています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#でODP.NETの自己流便利クラス(Bind変数利用)

概要

C#でODP.NETを使おうと思ったら大変だったので記事に残します。
自己流の自分用便利クラスなのでベストプラクティスは他にあると思います。
※環境はVisualStudio2019です

流れ

Oracle.ManagedDataAccsessのインストール
Oracleとの接続設定
Oracle操作用便利クラスの作成
便利クラスの使い方

Oracle.ManagedDataAccsessのインストール

プロジェクトを右クリックし、「NuGet パッケージの管理(N)...」を選択
参照で「Oracle.ManagedDataAccsess」を検索し、インストール

Oracleとの接続設定

いくつか方法があるようですが、今回はApp.Configを利用します。
Oracle.ManagedDataAccsessをインストールした時点でが生成されています。
そこに必要な情報を入力してください。
○○○:エイリアス
△△△:DBサーバーのホスト名orIPアドレス

※ここに入力する内容は、tnsnames.oraに登録してある内容と同じです。
※dataSources内には複数のdataSourceを入れることができます。

<oracle.manageddataaccess.client>
    <version number="*">
      <dataSources>
        <dataSource alias="○○○"
                descriptor="(DESCRIPTION = (ADDRESS = (PROTOCOL = tcp)(HOST = △△△)(PORT = 1521))(CONNECT_DATA = (SERVICE_NAME = orcl))) "/>
      </dataSources>
    </version>
</oracle.manageddataaccess.client>

Oracle操作用便利クラスの作成

あくまで自己流なので、より良い方法があれば教えてください。
一応Transactionも考慮しています。(未検証)

using Oracle.ManagedDataAccess.Client;
using System;

namespace common {
    class DbControl {

        // DB接続
        private OracleConnection conn;

        // SQL発行に必要
        private OracleCommand cmd;

        // SELECT時の結果読み取りに利用
        private OracleDataReader reader;

        // Transactionに利用
        private OracleTransaction transaction;

        // Bind変数に利用する型
        public static int DATE = 0;
        public static int VARCHAR2 = 1;
        public static int DOUBLE = 2;
        public static int INT16 = 3;
        public static int INT32 = 4;

        /// <summary>
        /// コンストラクタ:iniファイルから取得した情報でDBと接続し、接続(OracleConnection)を保持する
        /// </summary>
        public DbControl() {
            string connectString = "user id = " + Main.OracleLogonName + "; password = " + Main.OraclePassWord + "; data source = " + Main.OracleDbName;

            try {
                conn = new OracleConnection(connectString);
                conn.Open();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
                conn.Close();
            }
        }

        /// <summary>
        /// SQL文を使用し、OracleCommandを作成する
        /// <para>string sql:assets/sqlから取得したSQL文の文字列</para>
        /// </summary>
        public void SetCommand(string sql) {
            cmd = new OracleCommand(sql, conn);
            // バインド変数の名前解決
            cmd.BindByName = true;
        }

        /// <summary>
        /// バインド変数の設定
        /// <para>string parameterName:カラム名</para>
        /// <para>object parameterValue:カラムの値。string、DateTime等を渡す</para>
        /// <para>int oracleDbType:カラムのデータタイプ指定。DbManagementの定数を渡す</para>
        /// </summary>
        public void SetBindVariable(string parameterName, object parameterValue, int oracleDbType) {
            OracleParameter dbParameter = cmd.CreateParameter();
            switch (oracleDbType) {
                case 0:
                    dbParameter.OracleDbType = OracleDbType.Date;
                    break;
                case 1:
                    dbParameter.OracleDbType = OracleDbType.Varchar2;
                    break;
                case 2:
                    dbParameter.OracleDbType = OracleDbType.Double;
                    break;
                case 3:
                    dbParameter.OracleDbType = OracleDbType.Int16;
                    break;
                case 4:
                    dbParameter.OracleDbType = OracleDbType.Int32;
                    break;
            }
            dbParameter.ParameterName = parameterName;
            dbParameter.Value = parameterValue;
            cmd.Parameters.Add(dbParameter);
        }

        /// <summary>
        /// Transaction:開始(成功すればCommitを呼び、失敗したらRollBackを呼ぶ必要がある)
        /// </summary>
        public void BeginTransaction() {
            transaction = conn.BeginTransaction();
        }

        /// <summary>
        /// Transaction:コミット
        /// </summary>
        public void Commit() {
            transaction.Commit();
        }

        /// <summary>
        /// Transaction:ロールバック
        /// </summary>
        public void RollBack() {
            transaction.Rollback();
        }

        /// <summary>
        /// SELECT系のSQLで使用
        /// <returns>return OracleDataReader:</returns>
        /// </summary>
        public OracleDataReader ExecuteReader() {
            try {
                reader = cmd.ExecuteReader();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
            return reader;
        }

        /// <summary>
        /// 実行系のSQLで使用
        /// <returns>return Boolean:</returns>
        /// </summary>
        public Boolean ExecuteNonQuery() {
            int res = 99;
            try {
                res = cmd.ExecuteNonQuery();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
            if (res >= 1) {
                return true;
            } else {
                return false;
            }
        }

        /// <summary>
        /// DBのコネクションを閉じる(readerがあればreaderも)
        /// </summary>
        public void Close() {
            // 実行系だとnullになる為
            if (reader != null) {
                reader.Close();
            }
            conn.Close();
        }

        // 
        public static String GetString(OracleDataReader read, string target) {
            if (read.GetValue(read.GetOrdinal(target)).ToString() == "") {
                return "";
            } else {
                return read.GetString(read.GetOrdinal(target));
            }
        }

        // 
        public static int GetInt16(OracleDataReader read, string target) {
            return read.GetInt16(read.GetOrdinal(target));
        }

        // 
        public static int GetInt32(OracleDataReader read, string target) {
            return read.GetInt32(read.GetOrdinal(target));
        }

        // 
        public static float GetFloat(OracleDataReader read, string target) {
            return read.GetFloat(read.GetOrdinal(target));
        }

        // 
        public static String GetDateString(OracleDataReader read, string target, string format) {
            if (read.GetValue(read.GetOrdinal(target)).ToString() == "") {
                return "";
            } else {
                return read.GetDateTime(read.GetOrdinal(target)).ToString(format);
            }
        }
    }
}

便利クラスの使い方

SELECTしてみる

string sql = "SELECT name FROM Something WHERE hobby = :hobby;";

DbControl dbControlt = new DbControl();
dbControlt.SetCommand(sql);
// 第一引数はBind変数、第二引数は値、第三引数はカラムの型に合わせたもの
dbControlt.SetBindVariable("hobby", "山登り", DbControl.VARCHAR2);

OracleDataReader reader = dbControlt.ExecuteReader();
if (reader != null) {
  if (reader.HasRows) {
    while (reader.Read()) {
      Console.WriteLine(DbControl.GetString(reader, "name"));
    }
  }
}      

DbControl.Close();         

UPDATEしてみる

string sql = "UPDATE Something SET hobby = :hobby WHERE name = :name;";

DbControl dbControlt = new DbControl();
dbControlt.SetCommand(sql);
dbControlt.SetBindVariable("hobby", "川登り", DbControl.VARCHAR2);
dbControlt.SetBindVariable("name", "田中", DbControl.VARCHAR2);

OracleDataReader reader = dbControlt.ExecuteReader();
if (dbManagement.ExecuteNonQuery()) {
  Console.WriteLine("成功");
}else{
  Console.WriteLine("失敗");
}

DbControl.Close();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AndroidからPCへ加速度センサの値をUDPで送信する

プログラムの概要

今回のプログラムは、C#のコンソールアプリケーションで作成したサーバにAndroidの加速度センサの値をUDP通信で送信するものである。基本的にAndroid側で通信の制御をするので、C#側はただのエコーサーバを用いている。

プログラムのソースコード

activity._main.xml
<EditText
        android:id="@+id/IP_Address"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="52dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="192.168.0."
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/Port"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="48dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="8080"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/IP_Address" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="280dp"
        android:text="X:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:text="Y:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:text="Z:"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />

    <TextView
        android:id="@+id/X_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="280dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/Y_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toBottomOf="@+id/X_Data" />

    <TextView
        android:id="@+id/Z_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="TextView"
        android:textSize="32sp"
        app:layout_constraintStart_toEndOf="@+id/textView3"
        app:layout_constraintTop_toBottomOf="@+id/Y_Data" />

    <TextView
        android:id="@+id/textView7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="230dp"
        android:text="加速度センサの値"
        android:textSize="32sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/Ran"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="87dp"
        android:layout_marginLeft="87dp"
        android:layout_marginBottom="70dp"
        android:text="通信開始"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="IPアドレス"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/IP_Address"
        tools:layout_editor_absoluteX="16dp" />

    <TextView
        android:id="@+id/textView5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="ポート番号"
        android:textSize="24sp"
        app:layout_constraintBottom_toTopOf="@+id/Port"
        tools:layout_editor_absoluteX="16dp" />

    <Button
        android:id="@+id/End"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="87dp"
        android:layout_marginLeft="87dp"
        android:layout_marginEnd="87dp"
        android:layout_marginRight="87dp"
        android:layout_marginBottom="70dp"
        android:text="通信解除"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/Ran" />
MainActivity.java
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class MainActivity extends AppCompatActivity implements SensorEventListener{

    private SensorManager sensorManager;
    private TextView X_Data_TextView;   //加速度センサXの値
    private TextView Y_Data_TextView;   //加速度センサYの値
    private TextView Z_Data_TextView;   //加速度センサZの値
    private String Data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        X_Data_TextView = findViewById(R.id.X_Data);
        Y_Data_TextView = findViewById(R.id.Y_Data);
        Z_Data_TextView = findViewById(R.id.Z_Data);



        Button ran = findViewById(R.id.Ran);
        Button end = findViewById(R.id.End);
        ran.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final String address = ((EditText) findViewById(R.id.IP_Address)).getText().toString();
                String port = ((EditText) findViewById(R.id.Port)).getText().toString();
                int Port = Integer.parseInt(port);
                byte buf[] = new byte[Data.length()];

                try {
                    buf = Data.getBytes("SHIFT_JIS");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                InetSocketAddress inetSocketAddress = new InetSocketAddress(address, Port);
                final DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, inetSocketAddress);

                    AsyncTask<DatagramPacket, Void, Void> task = new AsyncTask<DatagramPacket, Void, Void>() {
                        @Override
                        protected Void doInBackground(DatagramPacket... datagramPackets) {
                            DatagramSocket datagramSocket = null;
                            try {
                                datagramSocket = new DatagramSocket();
                                datagramSocket.send(datagramPackets[0]);
                                datagramSocket.close();
                                //TimeUnit.MILLISECONDS.sleep(500);
                            } catch (SocketException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            } //catch (InterruptedException e) {
                               // e.printStackTrace();
                            //}

                            return null;
                        }

                    };
                    task.execute(datagramPacket);

            }
        });

        end.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String address = ((EditText) findViewById(R.id.IP_Address)).getText().toString();
                String port = ((EditText) findViewById(R.id.Port)).getText().toString();
                int Port = Integer.parseInt(port);
                String exit = "exit";
                byte buf[] = new byte[exit.length()];

                try {
                    buf = exit.getBytes("SHIFT_JIS");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                InetSocketAddress inetSocketAddress = new InetSocketAddress(address, Port);
                final DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, inetSocketAddress);

                AsyncTask<DatagramPacket, Void, Void> task = new AsyncTask<DatagramPacket, Void, Void>() {
                    @Override
                    protected Void doInBackground(DatagramPacket... datagramPackets) {
                        DatagramSocket datagramSocket = null;
                        try {
                            datagramSocket = new DatagramSocket();
                            datagramSocket.send(datagramPackets[0]);
                            datagramSocket.close();
                        } catch (SocketException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }

                };
                task.execute(datagramPacket);

            }
        });

    }



    @Override
    protected void onResume(){
        super.onResume();
        //Event Listener登録
        Sensor accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener((SensorEventListener) this,accel,SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause(){
        super.onPause();
        //Event Listener登録解除
        sensorManager.unregisterListener((SensorEventListener) this);
    }

    @Override
    public void onSensorChanged(SensorEvent event){
        if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
            X_Data_TextView.setText(String.format("%.3f",500+(event.values[0])*25));
            Y_Data_TextView.setText(String.format("%.3f",500+(event.values[1])*25));
            Z_Data_TextView.setText(String.format("%.3f",500+(event.values[2]) *25));
            Data = (500+event.values[0]*25) + " " +
                    (500+event.values[1]*25) + " " +
                    (500+event.values[2]*25);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy){

    }
}

Program.cs

static void Main(string[] args)
        {
            //バインドするローカルIPとポート番号
            string localIpString = "192.168.0.16";
            System.Net.IPAddress localAddress =
                System.Net.IPAddress.Parse(localIpString);
            int localPort = 8080;

            //UdpClientを作成し、ローカルエンドポイントにバインドする
            System.Net.IPEndPoint localEP =
                new System.Net.IPEndPoint(localAddress, localPort);
            System.Net.Sockets.UdpClient udp =
                new System.Net.Sockets.UdpClient(localEP);

            int i = 0;
            string[] xyz = { "X", "Y", "Z" };
            for (;;)
            {
                //データを受信する
                System.Net.IPEndPoint remoteEP = null;
                byte[] rcvBytes = udp.Receive(ref remoteEP);

                //データを文字列に変換する
                string rcvMsg = System.Text.Encoding.UTF8.GetString(rcvBytes);
                string[] RcvMsg = rcvMsg.Split(' ');
                //受信したデータと送信者の情報を表示する

                //"exit"を受信したら終了
                if (RcvMsg[0] =="exit")
                {
                    break;
                }

                for (i = 0; i < 3; i++) {
                    Console.WriteLine("{0}:{1}",xyz[i], RcvMsg[i]);
                }

                Console.WriteLine("送信元アドレス:{0}/ポート番号:{1}",
                    remoteEP.Address, remoteEP.Port);


            }

            //UdpClientを閉じる
            udp.Close();

            Console.WriteLine("終了しました。");
            Console.ReadLine();
        }

動作結果

キャプチャUDP.PNG
サーバ.PNG

課題

今回はサーバをコンソールアプリケーションで作成したが、フォームアプリケーションでの作成を目指している。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# Stack のシリアライズ

問題

コントリビュートをしているプロジェクトでシリアライズ/デシリアライズしているStackが毎回反転していることに気が付いた。公式ドキュメントや、NewtonJsonのIssueを発見して問題を理解したのでメモしておく。

        static void Main(string[] args)
        {
            var stack = new Stack<int>();
            stack.Push(1);
            stack.Push(2);
            stack.Push(3);
            var json = JsonConvert.SerializeObject(stack);
            Console.WriteLine(json);
            var restored = JsonConvert.DeserializeObject<Stack<int>>(json);
            var count = restored.Count;
            for (int i = 0; i < count; i++)
            {
                Console.WriteLine(restored.Pop());
            }
            Console.ReadLine(); 
        }

実行結果を見ると反転している。

[3,2,1]
1
2
3

分析

原因を知りたいところだが、Stackの公式ドキュメントを見ると、Stack<T>(IEnumerable<T>) のコンストラクタは、Stackにリバースして格納するようになっている。StackもIEnumerableを実装しているので

var stack = new Stack<int>();
var stack = new Stack<int>(stack);

とかするとオーダーが反転する。このあたりが問題かもしれない。こちらのチケットを見ると近い将来実装するかもしれない。このチケットを見ると、原因は、Json.NET の実装で次のようにいっている。

Deserialization: if the payload is "[1,2,3]", we return a stack with 3 at the top.
Serialization: if stack's contents are [1, 2, 3] with 3 at the top, we return JSON payload [3,2,1].

今デコンパイラが動かないので見れないけど、こういう振る舞いだというのは理解できた。

問題の解決

カスタムのシリアライザを書いているけど、カスタムなので復元の際にリバースさせることにした。

        public static TraceContextBase Restore(string json) 
        {
            if (!string.IsNullOrEmpty(json))
            {

                var typeName = JObject.Parse(json)["$type"];
                Type traceContextType = Type.GetType(typeName.Value<string>());

                var restored = JsonConvert.DeserializeObject(
                    json,
                    traceContextType,
                    new JsonSerializerSettings()
                    {
                        TypeNameHandling = TypeNameHandling.Objects,
                        PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                        ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                    }) as TraceContextBase;
                restored.OrchestrationTraceContexts = new Stack<TraceContextBase>(restored.OrchestrationTraceContexts);
                return restored;
            }
            else
            {
                return TraceContextFactory.Empty;
            }
        }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#でTypeInitializationExceptionが発生する

稀によくある"TypeInitializationException"が発生しがちな原因と原理の説明、および気を付ける点をまとめてみました。

詳細は以下からお願いします。
C#でTypeInitializationExceptionが発生する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む