プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

C#で値の入れ替え(Swap)

すごいテクニックとかじゃないです,ごめんなさい

昔作ったソースを久しぶりに開いたらR#先生から新しい教えをいただいたのでメモ

お題

2つの数値(a,b)の入れ替えをします

昔の

var a = 1;
var b = 2;

var temp = a;
a = b;
b = temp;

Console.WriteLine($"a={a} , b={b}"); // a=2 , b=1

プログラミングの勉強始めて1日目に書くコードですね. どんな言語でも同じような感じだとおもいます

新しい教え

var a = 1;
var b = 2;

(a, b) = (b, a);

Console.WriteLine($"a={a} , b={b}");

3行が1行になった!!

違い

↑の二つが同じものになるとは思えなかったので,ビルド後の生成物の値の入れ替え部分だけdnSpyでサクッと見てみます

昔の

int a = 1;
int b = 2;
int num = a;
a = b;
b = num;

新しいの

int a = 1;
int b = 2;
int num = b;
int num2 = a;
a = num;
b = num2;

新しい方はテンポラリー用の変数が増えています.デスヨネーという感じでですがまぁ誤差です.速度やメモリを気にする方は要注意でしょうか

まとめ

最近(?)のC#のバージョンからこのように書けるようになったんだと思いますが,これは私的には非常にありですね.

それにしてもこれをヒントで出してくれるR#先生(トップ画像)がすごいと思いました. おしまい

Windowsサービスを作るときに自動回復に頼りすぎてはいけない話

今回もやらかしネタをネタにしています。相変わらずちゃんとした裏どりはしていないのであまり信じすぎないでください。

自動回復オプション

Windowsサービスには自動回復のオプションがあります。基本的にWindowsサービスとして実行したいアプリケーションは常時起動している必要があるからサービスにしているわけで、停止していることがばれたら困るアプリの最後の砦として重宝します。クライアントアプリなどは操作中に落ちたら再起動をユーザーがすぐにしてくれますが、サービスの場合はそれが難しいですからね。

.NET Framework時代

太古の昔、C#( .NET Framework )でWindowsサービスを作ろうとしたときに重宝したのが Topshelf というライブラリで、コンソールアプリとして動かすこともできるしそのままサービスとして動かすこともできる、とても素晴らしいものでした。

先に書きましたがサービスとして動かすアプリですから、簡単に落ちてしまっては困ります。コード内で例外をキャッチしまくって落ちないようにするわけですね。

ですがなんでもかんでも例外を拾って無理やり動かしていても、ただ落ちていないだけで正常に動き続けているわけではないサービスになってしまい、最終的に落ちているよりたちが悪い状況を引き起こすかもしれません。

そこでWindowsサービスの自動回復の登場です。想定される(復旧可能な)例外はアプリ内で拾って、想定外の例外はそのまま放置でアプリを落としてしまいます。落ちたサービスはWindowsが指定時間後に再起動してくれるので、想定外だったけど再起動で直るような現象をこれでカバーしていました。

.NET 時代

現在Windowsサービスを作ろうと思ったら、Visual Studioで「ワーカー サービス」のテンプレートを使ってUseWindowsService()でしょう。

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .UseWindowsService()
    .Build();

host.Run();

これでWorkerの中でいろいろ処理をやるわけですが、今まで通りWindowsが指定時間後に再起動してくれるつもりで例外を拾わない、ように作ってしまうとやってしまいます。

これはログに

The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted.
Application is shutting down...

訳(?)「例外拾ってなくてBackgroundService 続けられないから終わるわ」

と出ているように、正常に終了しているのでWindowsはサービスがエラーで終了したとは認識してくれないからです。

自動回復の恩恵を受ける方法

継続不可能っぽいので再起動したいときにどうするのかというと簡単で

Environment.Exit(-1);

を呼ぶだけでいけます。かなり乱暴な方法なので最後の手段にしましょう。呼ぶときも解放できるリソースはできるだけ解放してからにしましょう。

というやらかしネタでした。

おしまい

.NET の浮動小数点と文字列化のちょっとした話

.NET Core (いつのバージョンかよくわかりません) での Breaking Change な話

var a = 0.0;
var b = -0.0;
Console.WriteLine(a == b);
Console.WriteLine($"{a.ToString() == b.ToString()} , a={a:f1} , b={b:f1}");

上記コードを .NET Framework 4.8 と .NET 6 のコンソールアプリで実行してみます

True
True , a=0.0 , b=0.0
  • .NET 6
True
False , a=0.0 , b=-0.0

という感じになります

"-0.0" って文字列が出てきて初めてこんな変更があったことを知りました

これかな?

devblogs.microsoft.com