.NET Interactive で C# と PowerShell を股に掛ける

この記事は、「C# Advent Calendar 2020」 9日目の記事、かつ 「PowerShell Advent Calendar 2020」 9日目の記事だ。

スミマセン。横着した。

この時期になれば .NET Interactive の Preview 4 が出てるだろうしその記事でも書こうかな~ などと目論んでいたものの、 残念ながら登場しなかった。

このため、 .NET Interactive .NET 5 対応版の導入と、 Variable sharing の内容でお茶を濁そうと思う。

.NET Interactive のなんたるかについては、以前の以下の記事で取り扱っているので、そちらを参照願いたい。

.NET Interactive を .NET 5 で動かしてみる

いきなり本題とは関係ない話になるが、 せっかく .NET 5 がリリースされたところなので、 .NET Interactive を .NET 5 で動かしてみよう。

続きを読む

大量の nanaco ギフトを自動登録して、オトクに税金を支払う

本記事は、 CUI のコンソール画面から使用する中級者向けのツールのに関する内容だ。
別途、 簡単に使用できる GUI 版も作成したので、そちらについては、以下の記事も参照。


突然だが、自動車税や固定資産税などの税金や、公共料金などの払込票などを、どのように支払っているだろうか?
支払う額も大きくなりがちなので、なるべくお得に支払いたいのではないだろうか。

そこでオススメなのが nanaco ギフト だ。

クレジットカードで直接納税したり nanaco 残高にチャージする場合、手数料がかかったり、ポイントがたまらなかったりと、あまりお得にならない。
しかし nanaco ギフトであれば、額面よりも安く入手する手段が知られている。

  • ベネフィット・ステーション
    • 福利厚生型の会員制割引サービス。
    • 2020年4月現在、 毎月 10万 円分まで 額面の 2% OFF で nanaco ギフトを購入できる。
    • 所属組織による団体加入か、 「ベネフィット・ステーション プライベート」 や 「デイリーPlus」などといった個人向けの有料サービス、 「(JACCS カードの) J’s コンシェル」などの付帯サービスで利用できる。
  • Kiigo (廃止)
    • 以前はクレジットポイントを貯めながら nanaco ギフトを購入できたのだが、 2019年 に nanaco ギフトの取り扱いがなくなってしまった。
  • ちょコムショップ
    • NTT系列の決済会社が運営する、電子マネー購入サイト。
    • 0.5% OFF 程度で、一部ブランドのクレジットカードを使って購入できる。 クレジットカードのポイントと併せればそこそこお得に購入できる。

また nanaco 残高と違ってセンターお預かりへのチャージなので、 チャージ残高の上限が非常に高く (50万円以上も可能らしい)、 nanaco 残高のチャージ上限である 5万円を超えるような金額の支払いでも使える大きなメリットがある。

nanaco ギフトでのお得な納税の話は、他のサイトでもっと詳しくわかりやすく書かれているだろうから、これくらいにしておく。

nanaco ギフトの登録がめんどくさい

さて、 ここからが本題だ。

そんな nanaco ギフトにもひとつ 大きな欠点がある。
それは、 1,000 円単位で提供されることが多い ということだ。

例えば 10万円分 チャージしようとすると、 100 回も nanaco ギフトID のコードを入力しなくてはならないのだ。

更に、 nanaco ギフトの登録を行う UI が、大量のギフト登録に とても優しくない
1回 コードを入力する毎に nanaco にログインしたり、 コードを 4文字 ずつテキストボックスに入力しなくてはならなかったりと、 数をこなすのにとにかく手間がかかるのだ。

10万円 の納税で 2,000円 得するために、 2,000円分 相当以上の手間をかけるのでは愚の骨頂だ。
こうなったら、自動入力させるしかない。

続きを読む

同一ファイルに対して、 複数種類のファイルハッシュを高速に計算する

ネットワークドライブ上の GB オーダーのファイルに対して、複数のハッシュアルゴリズムでファイルハッシュを計算する必要に駆られていた。
「そんなシチュエーションが本当にあるのか?」と思うかも知れないが、あったのだから仕方ない。

最初は、 PowerShell を使って 愚直に Get-FileHash を 2回 計算していた。
しかし当たり前だが、 2回ファイルをダウンロードすることになるこの方法は遅くて仕方ない。

ということで、 C# でコンパイルしたコード上で、 一度メモリに読み込ませてから複数のハッシュアルゴリズムで計算できるようなコードを作成した。

バッファーサイズを 80KiB 程度とすると、 .NET の仕様で 85KB を境にメモリの扱いが変わる (LOH と呼ばれる特別なヒープに移動する) ことから、 このサイズを超えると一般的に動作速度が下がると言われている。
しかし、今回のコードの場合バッファーが小さいと、 Task 周りの処理がボトルネックになってしまうので、 8MiB くらいのサイズとしている。

80KiB としているのは、 .NET mscorlib の System.IO.Stream.CopyTo メソッドなどでもおなじみなのだが、これが必ずしも正解とは限らないわけだな。


パフォーマンス

800Mbps 位でシーケンシャルリードできるリモート上の 4GB のファイルを、 4回 ずつ計測した平均を計測した。
Get-FileHash の 2種類目 以外はクライアントキャッシュが効かないように注意し、 計測の各回でハッシュを計算するファイルはそれぞれ別のファイルで、中身はランダムバイナリとした。
Get-FileHash については、 計測の各回では同じファイルに対して -Algorithm パラメータを変えて複数回連続で呼び出した。

計算したハッシュの種類 Get-FileHash 上記の改良スクリプト
1種類 (SHA1) 48.8s 43.3s
2種類 (MD5, SHA1) 60.4s 44.2s
3種類 (MD5, SHA1, SHA256) 83.3s 48.2s

ん? 計算したハッシュが 1種類 の場合でも、改良スクリプトの方が早いぞ?


うわっ… HashAlgorithm.ComputeHash の実行速度、低すぎ…?

PowerShell v5 相当

PowerShell v6 相当

上記のように、 Get-FileHash は、内部的に HashAlgorithm.ComputeHash でハッシュ計算を実行している。

で、その HashAlgorithm.ComputeHash がどうなっているかというと、 4KiB 毎に ファイルの読み込みと、 ハッシュストリームへの書き込みを 同期的に 行っている。

ファイルの読み込みも、 (使うアルゴリズムにもよるけど) ハッシュの計算も、 どちらもコストがかかるので、同期的にやってたらそりゃ遅いわ。

System.Data.SQLite の NuGet パッケージ のうち どれをインストールするべきか

この記事は、(この記事が初公開された日を基準にして) 4年前に投稿された

の記事のフォロー記事だ。

Visual Studio 2012 に標準で含まれて以降、 NuGet を使ってライブラリパッケージをインストールすることが標準的になった。
しかし、 System.Data.SQLite に於いては、 NuGet パッケージの方も相変わらず多くのパッケージが公開されているので、 これらについてもどれをインストールすべきか解説してみようと思う。 160620_1

Entity Framework Core について書いたひとつ前の記事の

とは異なり、 こちらの記事は Full .NET で SQLite を使う場合で、 特に Entity Framework 6.x と組み合わせる際に有用な内容となっている。
(残念ながら、 System.Data.SQLite は .NET Core では使えないのだ。)

公開されている NuGet パッケージ

続きを読む

DI っぽく EF Core 1.0 + SQLite を Full .NET と .NET Core のコンソールアプリケーションで使ってみる [Entity Framework Core]

しばやん御大の Entity Framework Core についての以下の記事を読んで、


コンソールアプリでも、 ソースコードに 接続文字列 や ログの設定を書かずに、設定ファイルから Dependency Injection (依存性の注入: 以下DI) するにはどうしたらよいのかな? と思ったので、 ASP.NET Core の流儀を参考にしながら やってみようと思う。

データベースは、扱いが簡単な SQLite にする。

記事の最後に、 Visual Studio 2015 ですぐに使えるサンプルプロジェクトを用意しているので、 手っ取り早く結果を見たければ、 そのサンプルプロジェクトを見てみてほしい。

実現すること

まずは、何を実現させるのかをハッキリさせておこう。

  1. 接続文字列と ログ表示の設定を、外のファイルから指定すること
  2. マイグレーションなどを行うため、 EF Tools からも、上記設定が利用されるようにすること

ここで言う EF Tools とは、Entity Framework Core の コマンドラインツール のことだ。
このツールを使うと、 パッケージマネージャーコンソールから Add-Migration とか Update-Database と実行したり、 dotnet.exe から dotnet ef コマンドを 実行することで、 コード生成やマイグレーションなど を利用することができる。

EF Tools でデータベースを取り扱う際、その接続文字列は DbContext に設定されたものが使用される。
コード内に接続文字列を書いてしまうと、マイグレーションするためのデータベースファイルが決め打ちになってしまい、変更ができなくなる。
このため、 EF Tools を実行した際も、依存性の注入が行えるようにしたい。

前準備

続きを読む

VS Express で .NET Core の xUnit.net を使ったテストのデバッグを行う

.NET で 単体テストと言えば、いまや xUnit.net が事実上の標準となっている。
ASP.NET Core や .NET Core のドキュメントでも、単体テストは xUnit.net を使うように案内されている。

ところが Visual Studio の Express Edition 系列 の テストエクスプローラは、 xUnit.net に対応していない。
それでも Full .NET Framework や dnx では、そのままテストプロジェクトを「実行」してしまえば、とりあえずデバッグ実行はできていた。
しかし、 .NET Core + dotnet-test-xunit では、それすらもできなくなってしまい、 dotnet test コマンドの出力を確認するしかなくなってしまった。

デバッグ実行ができないのは流石に不便… ということで、デバッグ実行を行うハックを紹介しよう。

# ライセンス的に Visual Studio Community 使えるのなら、そちらを使うべき。
# ただ、たとえ Express ではなくても、 この方法を使うと xUnit.net の出力が文字化けする問題も防げるぞ。

エントリーポイントを作成し、コンソールプロジェクトにする

続きを読む

.NET Core での コンソールアプリの文字化けを直す

だいぶ予定が遅れたようだが、 .NET Core 1.0 の RC2 が5月中旬にリリースされた。

2000年に初めて .NET がリリースされてから、 mono が登場したりといったことはあったものの、 16年越しでついに クロスプラットフォームのアプリケーションを作成できる環境が、マイクロソフト公式から提供された。

ということで、さっそく .NET から VS2015 DotNetCore Tools Preview 1 をインストールして、 Hello World を書いてみよう。

using System;
using System.Text;

namespace netcore_console_test_01 {
    public class Program {
        public static void Main(string[] args) {
            Console.WriteLine("はろー わ~るど!");
        }
    }
}

160530_1

…文字化けするぞ!!?

続きを読む

PowerShell で 配列をシャッフルする

コード

PowerShell で 極力簡単に配列をシャッフル (ランダムにソート) する方法。
速度や制度などはガン無視して、簡単に書けることを重視。

$shuffled = $array | sort -prop @{Exp={[Guid]::NewGuid()}}

ハイ終わり。

検証

ホントに実用的なシャッフルになっているか心配なので、実際に 0~19 のシャッフルを 2000 回行って、先頭に来た数字と、10 が来たインデックスを集計してみる。

$r = 0..1999
$r | %{ $r[$_] = 0..19 | sort -prop @{Exp={[Guid]::NewGuid()}}; }
$r | %{ $_[0] } | group | Format-Table -AutoSize
$r | %{ $_.IndexOf(10) } | group | Format-Table -AutoSize
Count Name Group
----- ---- -----
  104 16   {16, 16, 16, 16...}
   91 19   {19, 19, 19, 19...}
  111 8    {8, 8, 8, 8...}
  102 7    {7, 7, 7, 7...}
   95 18   {18, 18, 18, 18...}
  105 3    {3, 3, 3, 3...}
   95 12   {12, 12, 12, 12...}
   83 15   {15, 15, 15, 15...}
  100 17   {17, 17, 17, 17...}
   89 5    {5, 5, 5, 5...}
  103 13   {13, 13, 13, 13...}
  103 11   {11, 11, 11, 11...}
  101 10   {10, 10, 10, 10...}
  110 4    {4, 4, 4, 4...}
  100 6    {6, 6, 6, 6...}
   88 2    {2, 2, 2, 2...}
  123 9    {9, 9, 9, 9...}
   92 1    {1, 1, 1, 1...}
  107 0    {0, 0, 0, 0...}
   98 14   {14, 14, 14, 14...}

Count Name Group
----- ---- -----
  102 17   {17, 17, 17, 17...}
   93 15   {15, 15, 15, 15...}
  100 9    {9, 9, 9, 9...}
  109 18   {18, 18, 18, 18...}
   91 4    {4, 4, 4, 4...}
  104 5    {5, 5, 5, 5...}
  111 3    {3, 3, 3, 3...}
  107 7    {7, 7, 7, 7...}
   83 1    {1, 1, 1, 1...}
  106 10   {10, 10, 10, 10...}
  101 13   {13, 13, 13, 13...}
   93 8    {8, 8, 8, 8...}
  111 16   {16, 16, 16, 16...}
  101 0    {0, 0, 0, 0...}
   83 2    {2, 2, 2, 2...}
  104 14   {14, 14, 14, 14...}
  103 12   {12, 12, 12, 12...}
   98 11   {11, 11, 11, 11...}
   81 19   {19, 19, 19, 19...}
  119 6    {6, 6, 6, 6...}

だいたい 100 に収束しているし、問題ないんじゃない?

とはいえ、 Guid クラスは、一意性はある程度期待できると書かれているものの、ランダム性は特に言及されていない。
出現にパターンがある可能性もあるし、厳密にランダムである必要がある場合は、使わない方がいいかもしれない。

続きを読む