最近やったこと・やっていること

1. EXCELマクロをVBAで実装する案件を行いました。
VBAは一度読んだことがある程度だったので文法を調べつつだったのですが、
C#では手軽にコードレスに行えるところでも手間がかかるなどして、
想定以上に工数がかかってしまいました。
ですが必要な機能をひとまず実装してみて、コードを少しづつ洗練して行く過程は楽しかったので、
良い経験にはなったかなと思っています。

2. Pythonの環境構築や調査を行いました。
既存のPythonで書かれた処理をC#で置き換える案件のためです。
Pythonは学生時代に講義で習ったのと研究でグラフ出力するのに使用したことがある程度なのですが、
久しぶりだったのもあり楽しかったです。
得られた知見としては、特段の事情がなければ環境構築はAnaconda上で仮想環境を作成して行うのが良いということです。
今回まずはローカルの環境にpipでライブラリのインストールを行っていたのですが、
その際にcmakeでのビルドが必要だったりして中々上手く行きませんでした。
しかしAnacondaで試してみたらすんなり出来ました。
ライブラリの取得先がpipとは異なるからなのか、パスの設定などまで行ってくれるからなのか、
理由ははっきりわかっていませんが、
依存している他ライブラリのインストールまで含めて良しなにやってくれるようです。
pythonやライブラリのバージョン競合も防げますし、環境の削除も一発ですし、
本番環境でなければAnaconda上で済ませてしまいたいと思いました。

3. 私事ですが毎朝2,3分走っています。
朝は少しでも寝ていたいため毎朝ギリギリの時間に出発しているのですが、
3か月ほど前からは特にそれが顕著で、毎朝バス停まで走るはめになっています。
初めはぜぇぜぇ言いながら走っていたのですが、
最近は走るのが少し楽になってきて一周回って楽しくなってきました。
心なしか体力も向上した気がしており、仕事でも疲れにくくなったように感じています。
運動の重要性をひしひしと実感しております。

以上、近況的な投稿でした。

コロナに感染しました

題の通りで、先月末コロナに感染しました。
快復傾向に至るまで1週間ほどかかり社内メンバーにはご迷惑をおかけしてしまいました。

症状としては喉の痛みが少しあったのと、38-39℃ほどの発熱で、
発熱は連日続いたため大変しんどかったです。
発熱外来では解熱剤を貰えなかったのですが、
家にロキソニンが余っていたのでそれを呑んで耐え凌ぎました。
現在は快復はしたのですが、後遺症なのか痰が喉に絡み続けていて、
咳を出さざるを得ず若干過ごしにくいです。

社内メンバーにも家族にも感染を広げなかったのは不幸中の幸いでした。

開発担当の案件も遅れが出てしまったのですが、
社内メンバーに開発を手伝ってもらい、
本日無事納品することができて一安心しました。
(福岡さん、masugiさん、ありがとうございました。)

皆様お気を付けてお過ごしください。

WindowsFormにおけるコントロールの別ウィンドウ化

弊社で最も規模の大きなプロジェクトはWindowsFormにて開発が行われています。

先日、そのプロジェクトにてコントロールを別ウィンドウ化する処理を
既存の実装を参考にして実装したのですが、
予想以上に手軽に出来て驚きました。

以下のようにするだけでした。

// 別ウィンドウとなるフォームを作成
var window = new Form {
	Owner = this.ParentForm,
	Width = this.Width,
	Height = this.Height
};
// 別ウィンドウ化したい対象コントロールの親コンテナに新規ウィンドウをセット
// (別ウィンドウに移し替える)
targetControl.Parent = window;
// 別ウィンドウクローズ時に親コンテナを元に戻すように
window.FormClosed += (_, _) => {
	targetControl.Parent = this;
};
window.Show();

親コンテナのSetterは参照を移し替えるだけかと思い込んでいたのですが、
配置も移し替えるのですね。
便利に作られていてありがたいです。

栄養ドリンクと夏季休暇

皆さんは休日、どのように過ごされていますでしょうか。

自分は疲労により椅子に座る気力もなくベッドに転がってだらだらとスマホを弄るなど、
無をしてしまうことが多々あります。
流石にもっと精力的かつ有意義に過ごしたいと思い、
先々週から週末に栄養ドリンクのユンケルを1本飲むようにしてみています。
流行りのエナジードリンクでなく栄養ドリンクなのは、
エナドリは学生時代に飲み過ぎたせいか少し苦手になってしまったからです。
まだ2週だけですが、心なしか週末に心身共に元気な状態で過ごせた気がします。
(プラシーボかもしれませんが。。。)

ところで、弊社は明日から15日まで一応夏季休業となっております。
この連休も元気に過ごせるよう、ユンケルを飲んでおこうかなと思っています。
皆様もお体にはお気をつけて、元気にお過ごしください。

タプルを用いた値の交換

2つの値を交換したい時、皆さんはどのようにしていますか?

私は本日、以下のように愚直に行っていました。

var x = 1;
var y = 2;
var tmp = x;
x = y;
y = tmp;

スマートでないな~と思っていたのですが、
コードレビューにて同様の処理をタプルを用いて以下のように記述できるとの指摘を受けました。

var x = 1;
var y = 2;
(x, y) = (y, x);

う~ん、これはスマート!
(シンプルで可読性が高くて良いですね!)

タプルの構築と分解代入の複合により実現されるようです。
少し調べてみたところ、
コンパイル時には以下のような具合に最適化されるようです。

var tmp1 = y;
var tmp2 = x;
x = tmp1;
y = tmp2;

コンパイラも賢いですね!

今後もこのような知見を活かしてコードをシンプルに保てるようにしたい所存です。

(参考)
以下のサイトを参考に一部コードを引用させていただきました。
ありがとうございました。

複合型の分解 – C# によるプログラミング入門 | ++C++; // 未確認飛行 C

Linqによるソート:OrderByとThenBy

先日、あるクラスのソートのためにICompareble<T>を実装したラッパークラスを作成したのですが、
コードレビューの際にLinqのOrderByを使用すれば良いとの指摘を受けました。

以下のようなクラスとそのリスト、値の演算メソッドがあった際に、

class Hoge {
	public int No { get; set; }
	public int Value { get; set; }
}
var hogeList = new List<Hoge>(){ /* 要素たくさん */ };
int CalcHeavyForSort(int value) {
	var ret = 0;
	// 重い演算
	return ret;
}

次のように書くことで、

hogeList = hogeList.OrderBy(x => CalcHeavy(x.Value)).ThenBy(x => x.No).ToList();

1. Valueの演算結果により昇順でソート
2. 1によるソートの順序内でNoにより昇順でソート
を実行してソートされたリストを取得できます。

降順ならOrderByDescending, ThenByByDescendingです。
特殊な比較を行いたい場合は、IComparerを引数に与えることもできるようです。

引数で与えたラムダ式の実行も1要素1回だけのようですので安心ですね。
(内部でラムダ式の戻り値のリストを作成し、
インデックス同士を比較するメソッド内でその戻り値リストへアクセスしているようです。)

雑ですが、もしも次のようにソート時に同じ重い演算を複数回実行する必要がある場合は、

hogeList = hogeList.GroupBy(x => CalcHeavy(x.Value))
		.ThenBy(x => CalcHeavy(x.Value) * x.No).ToList();

次のように匿名クラスでラッパーを作り、それをソートすると良さそうに思います。

hogeList = hogeList.Select(x => new {
		Source = x,
		CalcedValue = CalcHeavy(x.Value),
	})
	.OrderBy(x => x.CalcedValue)
	.ThenBy(x => x.CalcedValue % x.Source.No)
	.ToList(x => x.Source);

Linqは便利で可読性が高く保守もしやすいので、
シビアなパフォーマンスが求められるケースでなければ積極的に使っていきたいです。

USBドライバインストール時エラーの対処

先日、USBカメラを接続するためにドライバのインストールを行ったのですが、
その際に以下のエラーが発生し、インストールに失敗しました。
「このハードウェアのデバイスドライバーを読み込むことができません。
 ドライバーが壊れているか、ドライバーがない可能性があります。(コード39)」

結論から言うとWindowsセキュリティ設定が原因で、

Windowsセキュリティ->デバイスセキュリティ->コア分離->メモリ整合性をオフに変更

により解決しました。
以下、解決までの過程です。

1. 試行錯誤
次のようなことを試したのですが、解決も原因特定もできませんでした。
・カメラやケーブル、接続ポートを変更
・メーカーHPにてドライバの対応OS, CPUの確認
・ドライバを最新のものに更新

2. PC初期化
社内の他のいくつかのPCでは問題なく成功しており、
PC自体に原因がありそうだったのでPCの初期化も行いましたが、
それでもインストールは成功しませんでした。

3. メーカー問い合わせ・解決
にっちもさっちも行かなくなり、メーカーさんに問い合わせたところ、
次の手順でWindowsのセキュリティの設定を緩めれば良いと教えていただき、
無事解決しました。
スタート->設定->更新とセキュリティ
 ->Windowsセキュリティ->デバイスセキュリティ
  ->コア分離->コア分離の詳細
   ->メモリ整合性をオフに変更

原因となったメモリ整合性、PCによっては出荷段階で既にオンになっているようなので、
ドライバのインストールに失敗した際には確認してみると良いかもしれません。

その後、本件について補足情報などないか検索していたところ、
エラーメッセージ+エラーコードがタイトルの記事に解決策が掲載されているのを発見しました。
プログラミングの際はエラー発生の初期段階でエラーメッセージの検索をするのですが、
今回は失念していました。今後は気を付けたいです。

Reflectionによるプロパティ名の取得

先日、クラスの持つプロパティ名をExcelファイルに列挙すると言った作業を行うことになりました。
対象となる複数のクラスから特定の条件を満たすプロパティの名前のみを列挙する必要があり、
始めは手作業で地道にコピーしていたのですが、途中でReflectionを用いれば自動で列挙可能だと気付きました。
プロパティには列挙条件を示す属性が付与されていたのですが、
属性を取得できることを失念していました。

取得には以下のようなコードを使用しました。
※正確に再現したコードではないのでミスなどあるかもしれません


private static List<string> GetHogeIsHugaPropertyNames(Type type) {
    return type.GetProperties()
               .Select(p => (p, Attribute.GetCustomAttribute(p, typeof(HogeAttribute)) as HogeAttribute))
               .Where(x => x.Item2 != null && x.Item2.IsHuga)
               .Select(x => x.p.Name)
               .ToList();
}

これに気付かなかったため時間を少し溶かしてしまいました。
何か作業する際は開始前に作業手順を確認し、
繰り返し手作業を行う必要があるようならどうにか自動化できないかを考えるようにしたいと思います。

ディスプレイサイズとコードの読みやすさ

2週間ほど前に業務で使用するディスプレイを新調していただけました。
23.5インチほど(解像度1920*1200)から31.5インチ(解像度2560*1440)になったのですが、
コーディングがやりやすくなって大変ありがたいです。
コードの表示領域が大きくなるとこれだけ変わるのかと驚いています。

特にコードの読みやすさが格段に上がりました。
今までは横に長いコードに読み辛さを感じていたのですが、
視野内中心部に余白有りでコードが表示できるようになり問題がなくなりました。

適宜改行を挿入して読みやすく整形しておくに越したことはないと思いますが、
開発者全員が大きなモニタを使用することが確かなプロジェクトであれば、
多少横に長いコードを書いても支障はないのかもしれませんね。

ReSharperのInlay Hints機能の表示切り替え

3カ月ほど前からVisualStudioに拡張機能のReSharperを導入しました。
リファクタの提案をしてくれたり、スニペットを登録できたりと、何かと便利に感じています。

そのReSharperなのですが、デフォルトで型推論varの実際の型であったり、
引数のパラメータ名であったりを表示してくれる機能 Inlay Hints があります。
この機能、他者が書いたコードを読む際には大変便利なのですが、
下記例のように1行が長くなってしまい、逆に不便に感じることがしばしばあります。

a
Inlay Hintsで冗長になる例

そこで、任意のタイミングでInlay Hintsの表示/非表示を切り替える方法があれば良いのにと思い調べてみたところ、
ReSharperの公式マニュアル[1]に記載されていました。
以下の方法でできるようです。

1. スクロールバー上部アイコンを右クリックして表示したコンテキストメニューから切り替える
2. エディタ上で Ctrl+Shift+Alt+5 ショートカットキーを押す
3. ResharperのOptions -> Environment -> Inlay Hintsで、
Enableのチェックを外す or visibilityをShowAlwaysから別の項目に変更する


1. InlayHintsコンテキストメニュー


3.-ReSharperのOptions

2は押すキー数が多く、3はOptionsウィンドウを開くのに一手間かかるので、
この中だと個人的には 1のコンテキストメニューが一番手軽だと感じました。

マニュアルには、visibilityをPush-To-Hintにすることで、
Ctrlキー長押し?やCtrlキー2回押しで表示を切り替えれる旨の記載があるのですが、
こちらは上手く再現ができませんでした。
圧倒的にこちらの方が手軽なので、VisualStudioにて再現できた方がいれば、
その手順など教えていただけると嬉しいです。

[1] インレイヒント | ReSharper: https://pleiades.io/help/resharper/Inline_Parameter_Name_Hints.html