プログラミングBlog

C# Xunit①

xUnitでテストコードを書く前に、参照ではまりました。

エラー

テスト対象のプロジェクトのフレームワークとテストプロジェクトのフレームワークを同じにしないとエラーがでる。
ソリューション構成
f:id:Tokuty:20210111221823p:plain
テスト対象プロジェクト:TestCollection
テストプロジェクトとテスト対象プロジェクトのターゲットフレームワークが異なっている場合はこんなエラーが出る。 (4.6.2の場合 f:id:Tokuty:20210111222208p:plain

解決方法

例えばテストしたいプロジェクトのフレームワークのversionが<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />の場合。
TestProject.csprojを開いてテストプロジェクトのターゲットフレームワーク<TargetFramework>net461</TargetFramework>に合わせてあげる。

他のフレームワークをテストしたい場合はMicrosoftのドキュメントにターゲットフレームワークに関して詳しく書いてありますので参考にする。 docs.microsoft.com

アプリ開発サークル勉強会② 開催日時 2021年1月9日(土) 7:00-9:00

JavaScript問題集

今日もこちらの問題集をすすめていきました。Q9-11
https://gist.github.com/kenmori/1961ce0140dc3307a0e641c8dde6701d

Q9.配列の中身を結合して表示する問題 について

Join

a,b,cの要素持った配列があります。

const array = ['a', 'b', 'c'];

arrayに対してjoin ※引数に関して後で検証

array.join("");
結果
abc

joinの引数に関しての検証を行いました。

array.join();
array.join("");
array.join(" ");
結果
a,b,c
abc
a b c

引数なしの場合はカンマ区切りで表示。 空の文字列を入れるとすべての要素が結合されます。 文字列を入れるとそれらの文字列で区切られます。

split

こちらはJoinの逆で文字列を配列にします。

var str = "abc";
str.split();
str.split("");
結果
[ 'abc' ]
[ 'a', 'b', 'c' ]

引数なしの場合は文字列を配列に入れます。
引数ありの場合は文字列を引数区切りで分割して配列に入れていきます。

var str = "a b c";
split.(a b c);
結果
[ 'a', 'b', 'c' ]

スペース区切りで配列になりました。

Q11.配列の中身を結合して表示する問題 について

sort

let arry = [{ id: 1, name: 'morita' }, { id: 2, name: 'kenji' }, { id: 4, name: 'uro' }, { id: 3, name: 'ken' }];

sort()を使いますが、function(a,b)で要素の一つ目と二つ目を比較することができます。

 var sortByArry = arry.sort(function (a, b) {
     return a.id - b.id;
 });

降順の場合はb.id-a.idのように順番を入れ替えるだけで実装可能。

var sortByArry = arry.sort(function (a, b) {
    if (a.id < b.id) {
        return -1;
    }
    if (a.id > b.id) {
        return 1;
    }
    return 0;
});

aとbを比較して0未満か0以上かで返却した結果、要素を並べ替えることができます。
0の場合は変更なし。
ただしブラウザによっては動かないため返却値が0未満か0以上かで要素を並び替えていきます。

結果
[
  { id: 1, name: 'morita' },
  { id: 2, name: 'kenji' },
  { id: 3, name: 'ken' },
  { id: 4, name: 'uro' }
]

JavaScript初学者向け問題集

今回は初めての人もおられたのでオリジナルの問題を作って解いてもらいました。
意外と楽しんでもらえたので満足。
問題を作ったりしていると、プログラミングの理解にもつながるので良いですね! github.com

JavaScript 繰り返し処理について。

JavaScriptの繰り返し処理について

配列に格納されている値をすべて表示させたい時に、にfor文もしくはforEachを使いますよね。
例えばこんな配列があったとします。
index番号と値を表示させてみましょう。

for

const array = ["A", "B", "C"];

for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

for文の場合は簡単ですね。インクリメントされているiを使うだけです。

結果
index:1 A
index:2 B
index:3 C

さて、foeEachの場合はどうしましょう。

forEach

const array = ["A", "B", "C"];

array.forEach(function (value, index, currentValue) {
    console.log(`index:${index}`, `value:${value}`, `currentValue:${currentValue}`);
});
結果
index:0 value:A currentValue:A,B,C
index:1 value:B currentValue:A,B,C
index:2 value:C currentValue:A,B,C

forEachの場合だとindexとcurrentValueを引数に指定してあげると index番号とcurrentValue現在の値が取得できます。
他の言語にもforEachがありますが、index番号はだいたい取れるのでおぼえておくと良さそう。 便利ですね!
どんな時に使うか問題を作ってみました。

オリジナル問題①

学校という連想配列に学年と名前を定義してみました。
これらに対してforEachを使ってindex番号を取得し、
学年と出席番号をindex番号付きで表示させてみましょう。
例:学年1 出席番号1 名前

const school = {
    first_grade: [
        "丈太郎", "丈二郎", "常三郎"
    ],
    second_grade: [
        "NARUTO", "SASUKE", "SAKURA"
    ],
    third_grade: [
        "三男", "次男", "長男"
    ]
};

答え

Object.keys(school).forEach(function (key, index) {
    var grade = index + 1;
    school[key].forEach(function (value, index) {
        console.log(`学年:${grade}`, `出席番号:${index + 1}`, `名前:${value}`);
    });
});

Object.keys(school)でschoolのkeyの値をすべて取得することができます。
その後school[key]でvalue値、名前の配列を呼び出しています。
var grade = index + 1;で学年を取得。

結果
学年:1 出席番号:1 名前:丈太郎
学年:1 出席番号:2 名前:丈二郎
学年:1 出席番号:3 名前:常三郎
学年:2 出席番号:1 名前:NARUTO
学年:2 出席番号:2 名前:SASUKE
学年:2 出席番号:3 名前:SAKURA
学年:3 出席番号:1 名前:三男
学年:3 出席番号:2 名前:次男
学年:3 出席番号:3 名前:長男

感想

forEachでindex番号を定義して ランキングを出したり今回みたいに出席番号などに利用できるので便利ですね。
MDN見ていたら他にも書き方があるようなのでまた試してみようかと思います。

C# Threadの例外をCatchする。

Threadを使った非同期処理時に例外が発生した場合の動作について。

Excute()

Threadの実行クラス。ここでGreet()メソッドを呼び出します。

public static void Excute() {
          try
          {
              Thread thread = new Thread(new ThreadStart(Greet));
              thread.Start();
          }
          catch (Exception ex)
          {
              Console.WriteLine(ex.Message);
          }
          finally
          {
              Console.WriteLine("終了");
          }
}

Greet()

挨拶するクラス。 挨拶失敗して例外発生します。

public static void Greet(){
          try
          {
              // ここで例外発生!
              Console.WriteLine("Hello");
          }
          catch (Exception ex)
          {
              Console.WriteLine(ex.Message);
              throw ex;
          }
}

期待している動作としては Greetメソッドにて例外発生した後、throw exでExcuteメソッドに投げた例外をcatchしてほしい。 その後のfinallyにて終了を表示してほしい。
なんかエラーが出ました。。
f:id:Tokuty:20210106204054p:plain
Greetメソッドの例外でエラーが出てしまい、動作が終了しました。
ハンドルされていない例外、例外がCatchされなかったようです。
今の状態だと例外が発生した時点で処理が終了してしまうので期待している動作ではありません。

Excute() 修正版

Excuteメソッドを修正しました。

public static void Excute() 
      {
          Thread thread = new Thread(() =>
          {
              try
              {
                  Greet();
              }
              catch (Exception ex)
              {
                  Console.WriteLine(ex.Message);
              }
          });
          thread.Start();
}

無事動きました!デバッグで確認しましたが、Greet()が先に呼ばれそうでしたが、
thread.Start()が呼ばれてからGreet()が呼ばれていたのでこの書き方でもいけるようです。

感想

Threadが古い書き方で今はTaskを使うのが主流みたいですが、Replace案件が最近増えている(COBOLC#,VB6→C#などなど)ので、 Threadも扱えた方が良い。
非同期、同期の考え方自体が難しいので簡単なアプリを作って動作確認しながらやるのが一番わかりやすそう。
動くけど、今回のように不具合が発生する場合もあるのでいろいろ試した方が良さそう。

C#、WindowsServiceのexeの場所変更方法メモ

exeの場所について

プロジェクト→プロパティ→ビルド→出力 f:id:Tokuty:20210105215034p:plain 例えばこの状態でデバッグすると、 bin\Debug\フォルダの中にexeが置かれます。
出力場所を変更することで置く場所を変更することができます。

パスの取得

次はC#でパスを取得してみます。以下の3種類のやり方はどれも同じパスが取れます。
AppDomain.CurrentDomain.BaseDirectory;
Directory.GetCurrentDirectory();
Environment.CurrentDirectory;
bin\Debug\直下のパスを取得できることの確認。 f:id:Tokuty:20210105220432p:plain

感想

出力パス設定について知らなかったので結構詰まりました。
出力パスを変更することで読み込む位置が変わってくるのでもし設定ファイルを読み込んだりするときは注意が必要。

アプリ開発サークル勉強会① 開催日時 2021年1月2日(土) 19:40-21:00

JavaScript問題集

今日はこちらの問題集をすすめていきました。
https://gist.github.com/kenmori/1961ce0140dc3307a0e641c8dde6701d
Q.1からよくわからなかったのでいろいろやってみました。

学習メモ

Q1.の連想配列をマージして結果を表示する問題
Object.assign(target, source);

developer.mozilla.org

Object.assign() メソッドは、すべての列挙可能な自身のプロパティの値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。

連想配列連想配列をマージした場合

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 }; 
const result = Object.assign(target, source);
// 結果 { a: 1, b: 4, c: 5 }
  • targetがコピー先
  • sourceがコピー元
  • resultが結果
    targetの中身を見ると{ a: 1, b: 4, c: 5 }となっていたのでsourceがtargetにコピーされていました。同じkeyがある場合は上書きされる。

配列と連想配列をマージした場合

const target = { a: 1, b: 2 };
const source = ['b', 'd'];
Object.assign(a, d)
// 結果 { '0': 'b', '1': 'd', a: 1, b: 2 }

普通にできました。keyを設定していない場合は自動で連想配列に変換されてindex番号がついてくる。

配列と配列をマージした場合

const target = ['a', 'b'];
const source = ['b', 'd'];
console.log(Object.assign(target, source));
// 結果 [ 'b', 'd' ]

コピー先の値がなくなりました。

すべての列挙可能な自身のプロパティの値

プロパティの値がないからかな??

その他

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
// c:5
target.c = source.c;

// c:5
target['c'] = source.c;

// Key全件取得
Object.keys(target);

// 削除
delete target['a'];

感想

はまりポイントとしては配列と連想配列の違いをよく理解していなかった。
頑張って連想配列をpushやconcatしようとしてました 笑
keyとvalue形式はAPIで値を取得した際にもよく使うので今回使ったメソッドは覚えておくと便利そう。

WindowsService MEMO

結構はまってしまったのでService登録メモ。

f:id:Tokuty:20201227115637p:plain 管理者にて起動。
user + passwordを入力せずにできるようにしているため、管理者権限で起動しないとInstall時にSecurityでエラー出ます。

Service.exeが置いてあるフォルダにてinstallutil CountService.exe入力
UnInstallしたければinstallutil /u CountService.exe入力

f:id:Tokuty:20201227120755p:plain
Service起動して開始押したら起動します。
f:id:Tokuty:20201227120620p:plain

謎のエラー

こちらのエラーにかなり悩まされました。
f:id:Tokuty:20201227121242p:plain
DEBUGモードを記述していたためErrorが出ていた模様。
消したら起動できました。

ErrorCode

#if DEBUG
            Console.WriteLine("Start");
            NewService myService = new NewService();
            myService.OnDebug();
#else

            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new NewService()
            };
            ServiceBase.Run(ServicesToRun);
#endif

SuccesCode

ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new NewService()
            };
            ServiceBase.Run(ServicesToRun);