一人情シスのつぶやき

名古屋の中小企業で一人情シスをしている作者が、日々の業務で思うことをつぶやきます。

PowershellのToStringの書式指定ではまった

PowerShellのToStringで数値を書式指定で出力する際にはまった2点。どちらもエラーメッセージが適切ではなく、原因特定に苦労した。 PSVersion 5.1.14393.2969, Windows Server 2016上のISEで開発。Set-StrictMode -Version latest

書式#,#はダメ

$num.ToString('#,#') 

にて$numが0だと「"ToString" のオーバーロードで、引数の数が "1" であるものが見つかりません。」と出る。

$num.ToString('#,0')

とすることで、正しく出力される。

キャスト後のtoString

$s_num="99,999,999,99" 

の場合に書式指定で出力したい場合、いったんlongにキャストするので

[long]$s_num.ToString("#,0")

と書くと、同様に「"ToString" のオーバーロードで、引数の数が "1" であるものが見つかりません。」とでる。正解は

([long]$s_num).ToString("#,0")

キャスト演算子よりもToStringの方が優先度が高いのか...

.netで利用可能な帳票ツール

内製開発している.net(C#)で利用可能な帳票ツールについて調査した。結論としては、高いお金を出さないとまともなツールは手に入らないということ。 価格はすべて税抜き。

使えるが、高い

  • Create!Form: 1帳票設計ライセンス200,000円、1WindowsServerランタイム400,000円。帳票ツールは使いやすそうで機能も十分そうだが、高い...
  • Active Reports for .Net 12.0: 1開発ライセンス300,000円、サーバーライセンス(2core)120,000円。Create!Formと同様、機能は十分だが高い...
  • iTextSharp: 保守されている最新のVer.7(iText)では、ライセンスがAGPLかCommercial License。Commercial Licenseの費用は見積もりを取らないとわからないっぽいが、このサイトによると、1920ポンド(26万程度)..
  • JasperReport: Jaspersoft Studioという設計ツールで設計は簡単そう。.Netから利用しようとすると、Serverを立ててAPI経由での利用だがCommunity ServerのライセンスがAGPLか商用ライセンスの購入が必要。価格は見つけられなかったが、上記製品と同価格帯だろう。... LibraryはLGPLなのに... クライアントをJavaで開発するのは、今の自分の開発スキル的につらい、つらすぎる...

安いが、あまり使えない

  • Reports.net: 1開発ライセンス60,000円、ランタイムは無料。ヘルプ等を見る限り、ヘッダ・フッタやグルーピングという概念がなく、すべての項目を項目名を指定して出力し、ページ送りも自分で行う感じに見える。Excelに自分で出力するのと大差ない。
  • VB-Report 8: 1開発ライセンス85,000円、ランタイムは無料。Reports.netよりもさらに原始的で、ひな形Excelのセル番号を指定して出力する感じ。ひな形ExcelにClosedXMLあたりで出力したほうが早いやん。
  • Access: 14,800円。ランタイムは無料。一部内製アプリで使用しているが、 VBAは見捨てられた言語だし、ソースコードはいったんExportする必要があり、かつ元のバイナリには戻せない。開発しづらい。

無料だが、つらい

  • [Microsoft ReportViewer]: Visual Studio Proに添付。どっちにしろうちの開発用途ではCommunityは使えないので。ただ、社内帳票でよくある、1明細が複数行にわたる場合に対応できない。
  • ClosedXML.Report: 無料。よさそうだが、こちらも、1明細が複数行にわたる場合に対応できないっぽい。
  • 帳票.NET: 無料。最終リリースが2016年。継続性に不安
  • Excel: 全利用者に配布済みなので追加費用不要。ClosedXML等を利用して普通にセル指定で出力。プログラムで頑張ってセルを指定して出力するか、ひな形にてデータの表示とは別にデータの入力個所をまとめておいてプログラム側の負荷を下げるか、どちらにしてもめんどい。帳票の種類が増えてくるとつらさが増してくる。

まともなツールは1開発者でも300,000円から400,000円程度は最低でも必要なのだろう。が、中小企業においてこの金額はおいそれとは出ない。今後も継続的にバージョンアップする必要があるだろうし。 ひとまず、帳票部分のみAccessで開発、そのAccessを.netプログラムに同梱して帳票部分で呼び出す形にできないか調査、ダメならExcelのひな型をなるべく工夫する。あまりにつらくて上記費用が安いと感じられるようであれば購入を申請する形か。

Get-ChildItemからのLengthプロパティでのファイル容量取得ではまる

PowerShellで特定のフォルダ配下に存在する一定容量以上のファイルをリストアップするスクリプトを作成。

Get-ChildItem -Recurse  . | Where-Object{$_.Length -ge 10*1024*1024 }

よくあるお題であちこちにサンプルがあるのだが、なぜかLengthプロパティがないというエラーが出る。

色々調べた結果、Set-Strictのversionを2以上にすると発生することが分かった。1の場合には存在しないプロパティでも無視することで動作するようだ。

winscript.jpstackoverflow.com によると、対象がdirectoryの場合に配下のFileInfoとDirectoryInfo配列のサイズを返すところ、配下が1つのみの場合だと存在するFileInfo,またはDirectoryInfoのLengthを返そうとするためで、無理やり配列にすればいけるとあるが、ダメ。Directoryに対しては配下にファイルが無くても、何個あってもLengthプロパティへの問い合わせはエラーとなる。PowerShell Ver.5.1.17763.503 on Win10 1809(64bit)で確認。

結論としては、Directoryの中の個数をカウントしてもしょうがないので、対象をファイルのみにすることだった。

Get-ChildItem -Recurse -File . | Where-Object{$_.Length -ge 10*1024*1024 }

これであれば、Set-StrictのVersionがlatestでも通る。

ClosedXMLにて印刷範囲が設定され、「(」を含むシート名を保存するとファイルが壊れる

ClosedXML 0.93.1, 0.94.2で確認。

印刷範囲を設定したファイルを開いて、「(」を含むシートを作成して保存すると、ファイルが壊れてしまいExcelでは開けなくなる。 workbook.xmlを見る限り、シート名をシングルクォーテーションでエスケープできていないのが問題のようだ。 再現ケースを確定してIssueに挙げるか。

Form Load時にRadioButtonのCheckedChangedイベント発生

C# WinFormにてForm Load時にRadioButtonのCheckedChangedイベントが発生する事態に遭遇。 LoadイベントではCheckedをFalseにしているだけだし、他に怪しいイベントも見当たらない。

原因はTabStopが設定された、最小のTabIndexを持つフォームがRadioButtonになっていたため。

C#でのCollection系オブジェクトの受け渡し指針

C#でCollection系オブジェクト(IEnumerable, ICollection, IList等)の受け渡しをどうすべきか悩んでいた。 ListよりIList, EnumerableよりIEnumerableといった実装を含まないInterfaceが好ましいのは当然として、 あらゆるオブジェクトを想定してより抽象的なクラスを選択すべきというのは感覚的にわかるのだが、どうもしっくりこない。

以下の記事を見てなるほどと思った。 IEnumerable vs IReadOnlyList - Enterprise Craftsmanship

言語に依存しない一般的な方針としては、Postel’s law.として知られる(初めて知った...)

 be conservative in what you send, be liberal in what you accept, 

C#における具体的な方針として

prefer IEnumerable when accepting a collection; prefer IReadOnlyList when returning one.

確かに、引数は抽象的な方が使いやすいが、戻り値も抽象的だと結局toListしたりcastしたりしないといけないので使いにくいし、そもそもそんな使い方が正しいとは思えないので違和感があった。

IEnumerable - ICollection - IListという階層関係があるので、引数としてconservativeな(他の継承クラスも受け取れる)IEnumerableがよいというのはそのとおりだろう。 ただ、be liberal であるための解としてIReadOnlyListがあげられているが、これは利用側で内容を変更しないことがはっきりしている場合だろう。変更することが想定する場合はIListを返すべきと思われる。

複数のオブジェクトを格納する際には、IListの実装クラスがほとんどなので、これ以外を考慮する必要はとりあえずないと思われる。 DictionaryやHashtableを使う場合はIDictionaryあたりを返すのが妥当か?

CentOS 7のRedmine 4.0でrmagick build error.

CentOS7のDockerコンテナにてRedmineを構築中にrmagick buildにてエラー発生。 先週は動作したのだが...

ログを見ると、rmagickのバージョンは3.0.0で要求するImageMagickは6.8.9以上。インストールされているのは6.7.8Q16のためエラーとなっている。

このrmagick3.0.0は2月16日にリリースされたばかりらしい。その際に要求するImageMagickのバージョンが上がったのだろう。 rubygems.org

CentOSリポジトリでは最新でも6.7しかない。remiリポジトリにあるようなのでインストールしたところ、buildエラーがなくなった。

rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 
yum -y install ImageMagick6 ImageMagick6-devel --enablerepo=remi