デザイン

弊社が作成するソフトは工場で使用されるものが大半。
そのため、デザインはあまり気にされません。というよりはデザインにコストをかけることは喜ばれません。

しかし、現在開発を行っているソフトは外販の可能性もありデザインにコストをかけて良く、私が関わってきたソフトで一番凝ったデザインのソフトになっています。

私の兄がフリーランスとしてデザイン会社を営んでおり(https://m-code.jp/)、以前から一緒に仕事が出来ればと思っていましたが、とうとう実現しました。
兄は普段WEBデザインやCGデザインを行っており、パナソニックやオンキョーなどの案件を担当していますので実力は十分。お客様からもとても良い評価を頂きました。

SSD

最近、会社で使用しているデスクトップPCとノートPCをSSDに交換しました。
NVMeなのでHDDに比べて、シーケンスアクセスで10倍、ランダムアクセスで100倍近く高速です。

PC操作時の色々なタイミングで速度を実感でき、快適に開発が行えるようになりました。

ActionデリゲートやFuncデリゲートでタプルを使用

またC#のタプル(ValueTuple)の話です。

ActionデリゲートやFuncデリゲートは、複数個の引数を指定することができます。
例えば以下のようにstring型の引数を2つ受け取るActinデリゲートを受け取るHogeメソッドが定義できます。
(実装内容に意味は無いのであくまで参考の実装です)


void Hoge(Action<string, string> action) {
    action("aaa", "bbb");
}

これで動くのは動きますが、2つのstring引数が何者なのかコードからは全く読み取れないですね。
このメソッドを作った本人で無いと使用できないメソッドになっています。
今までならなせいぜいXMLコメントに引数の意味を記載してメソッド使用者に伝えることになります。
XMLコメントに「第一引数は名前、第2に引数はIDです。」みたいなことが書いてあれば、利用者は以下のように実装が可能でしょう。


Hoge((name, id) => {
    Console.WriteLine(name);
    Console.WriteLine(id);
});

しかし、タプル(ValueTuple)を使用すれば、このような問題は解決します。
先程のHogeメソッドを以下のように変更し、string型2つを保持するタプル変数1つにします。


void Hoge(System.Action<(string Name, string Id)> action) {
    action(("aaa", "bbb"));
}

これならば、2つのstring型に名前が付き、いちいちXMLコメントに記載しなくても最低限の意味は分かるようになりました。(あくまで最低限。XMLコメントが不要ということでは無いです。)
利用者側の実装は以下のようになります。


Hoge(x => {
    Console.WriteLine(x.Name);
    Console.WriteLine(x.Id);
});

「建設業の足元にも及ばない、IT業界は最も遅れた労働集約型産業だ」について

今朝見た日経XTECHの以下の記事が面白かったです。
「建設業の足元にも及ばない、IT業界は最も遅れた労働集約型産業だ」

我々IT技術者が良く比喩に使う建築業よりも遅れた業界だったとは!

私はこの業界に入ってソフト開発会社2社に勤めましたが、どちらもSIer無しの1次受けで、自社内での受託開発でしたので、この記事に書いているような多重請負でのIT土方な現場には関わったことがなく(関わりたくないですが)、驚くとともに技術者が可哀想になります。

このような現場では、志が高い技術者が入ったとしても、続かないか腐っていきます。結果、知的技術者はいなくなり、労働者だけしか残らいない技術者デフレスパイラルになってしまう。もったいない。

私は、志が高い技術者はベンチャー系会社に入ったほうが幸せだと考えています。
いまの日本のソフトウェア業界では、やりがいがあり・技術力が身につき・成果が収入になるのはベンチャーだけです。

つまり何が言いたいかというと、「インフォテックはベンチャー系なので、やる気のある技術者はぜひ面接に来てください」ということです。

タプル戻り値の要素数を増やす方法

C#7で追加されたタプル(ValueTuple)によって戻り値を複数返すことが出来るようになりました。


■タブルを使用した戻り値の例

public (bool b, string s) GetTuple() {
    return (true, "AAA");
}

public void Sample() {
    var (b, s) = GetTuple();
}

ここで1つ疑問が出てきました。機能追加によってGetTupleメソッドの戻り値を1つ増やしたいが、GetTupleメソッドを使用しているコードを変更したくない場合、どうすれば良いのか。

まず、バイナリ互換性を維持するのであれば、オーバーロードで複数のGetTupleメソッドを作成する方法が思いつきます。


■GetTupleメソッドのオーバーロード例 ビルド出来ません。

public (bool b, string s) GetTuple() {
    return (true,"AAA");
}

public (bool b, string s,string s2) GetTuple() {  
    return (true, "AAA","BBB");
}

public void Sample() {
    var (b, s) = GetTuple();
}

しかし、これではうまく行かないです。
C#は戻り値違いによるオーバーロードは出来ないからです。
引数を変えるか、メソッド名を変える必要があります。

次に、タプル(ValueTuple)を分解する拡張メソッドを作成し、3要素のタプルから2要素だけ分解する方法を考えました。


■分解拡張メソッド(Deconstruct)の例 ビルド出来ません。

public (bool b, string s,string s2) GetTuple() {
    return (true,"AAA","BBB");
}

public void Sample() {
    var (b, s) = GetTuple(); 
}

↓この分解拡張メソッドはstaticクラスに実装
public static void Deconstruct<T1, T2, T3>(this System.ValueTuple<T1, T2, T3> tuple, out T1 v1, out T2 v2) {
    v1 = tuple.Item1;
    v2 = tuple.Item2;
}

分解拡張メソッドは複数実装できるはずなのですが、なぜか追加した分解拡張メソッドは呼び出されませんでした。

結果、どの方法もうまくいきませんでした。
.netで標準的に要素数の少ない分解が出来るようになってほしいと思うのですが、出来ないということは何かリスクがあるのでしょうかね。

iOS用の社内ライブラリ

iPhone用アプリの開発でWindows用社内ライブラリに入っているクラスを使うことになり、せっかくなのでiOS用社内ライブラリを作成しました。

以前UWP用社内ライブラリを作成したときに共通化できそうなソースコードは共有プロジェクトに移動したので、今回は簡単にiOS用社内ライブラリが出来上がりました。
Xamarinの互換性の高さに驚きです。

WindowsFormsのコントロールの背景色やフォントが設定されているかを取得

最近、WindowsFormsのコントロールの背景色やフォントが設定されているかを取得する必要があったので、Controlについて調べてみました。
なお、背景色やフォントは親コントロールから継承されるので、普通にBackColorプロパティやFontプロパティでは設定されているかを調べられません。

以下のサイトでControlのソースコードを調べました。
Reference Source

結果、internalなRawBackColorプロパティとIsFontSetメソッドをリフレクションで実行すれば取得できそうです。

実装は以下のようになります。


public static class ControlExtension {
    private static Func RawBackColorDelegate { get; }
    private static Func IsFontSetDelegate { get; }

    static ControlExtension() {
        RawBackColorDelegate = typeof(Control).CreateGetPropertyDelegate<Func>("RawBackColor", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
        IsFontSetDelegate = typeof(Control).CreateMethodDelegate<Func>("IsFontSet", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
    }

    public static Color RawBackColor(this Control ctl) {
        return RawBackColorDelegate(ctl);
    }

    public static bool IsFontSet(this Control ctl) {
        return IsFontSetDelegate(ctl);
    }
}

public static class TypeExtension {
    public static TDelegate CreateGetPropertyDelegate<TDelegate>(this Type type, string name, BindingFlags flags) {
        var property = type.GetProperty(name, flags);
        var info = property.GetGetMethod(flags.HasFlag(BindingFlags.NonPublic));
        return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), info);
    }

    public static TDelegate CreateMethodDelegate<TDelegate>(this Type type, string name, BindingFlags flags) {
        var info = type.GetMethod(name, flags);
        return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), info);
    }
}

Controlの拡張メソッドにしましたので、全てのコントロールで使用可能です。
毎回リフレクションは遅いので、staticコンストラクタであらかじめデリゲートを作成しています。
ついでに、Delegate.CreateDelegateメソッドをラップする拡張メソッドも作成しました。

スプリッタコントロール

今月はC#のSplitterコントロールとSplitContainerコントロールの2つのスプリッタコントロールに機能追加を行いました。

スプリッタコントロールは以下の画面のように、2つの領域をマウス操作で可変にするコントロールです。
なお、この画面は弊社で作成している社内用の画像処理ソフトです。

追加したのは以下の機能
1.マウスオーバー時に色を変更する処理
2.ダブルクリックで一方の領域を最小化したり元のサイズに戻したりする処理

この機能追加を社内ライブラリにおこないましたので、今後のアプリではこの機能が簡単に使用できるようになります。

今回対応したのはWindowsFormsだけなので、いずれWPF用にも対応を行う予定です。

Xamarin.Formsを使用してWindowsデスクトップアプリ開発

モバイル用のクロスプラットフォームUIツールキットのXamarin.Formsですが、Windowsデスクトップアプリにも使えるようになるそうです。今後使うかも知れないのでとりあえずメモ。

https://qiita.com/tan-y/items/cf5088c6853ebb1b6c64
https://qiita.com/tan-y/items/e08d297c2d013214eb83

C#のZip拡張メソッド

以前にブログに記載しました、C#7で追加された分解の機能に関係するお話。

この分解が増えたことで、LINQのZip拡張メソッドをもっと使いやすくできるのではなかろうかと思い、新しいZip拡張メソッドを作成してみました。

まず、いままでのZip拡張メソッドの例。


var xArray = new[] { 1.1, 2.2, 3.3 };
var yArray = new[] { 4.4, 5.5, 6.6 };
foreach (var item in xArray.Zip(yArray, (x, y) => new { x, y })) {
    Console.WriteLine($"X={item.x} , Y={item.y}");
}

xArrayとyArrayをマージして新しい匿名クラスを作成しています。
匿名クラスを作成するラムダ式を指定するのが面倒ですね。

で、新しく追加したZip拡張メソッドを使用すると以下のようになります。


var xArray = new[] { 1.1, 2.2, 3.3 };
var yArray = new[] { 4.4, 5.5, 6.6 };
foreach (var (x, y) in xArray.Zip(yArray)) {
    Console.WriteLine($"X={x} , Y={y}");
}

匿名クラスを使用せず、Tupleクラスのインスタンスを返すようにしました。
C#7で増えたタプルではなく、昔からあるTupleクラスなので、通常ならば値にアクセスする場合、item.Item1やitem.Item2などのようにxやyの名称がなくなり可視性が悪いですが、分解のお陰で、xとyの名称そのままで値にアクセスできるようになりました。

ちなみに、新しく作成したZip拡張メソッドの実装は以下となります。


public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(this IEnumerable<T1> items1, IEnumerable<T2> items2) {
    return items1.Zip(items2, (item1, item2) => Tuple.Create(item1, item2));
}

同じようにして、3つのシーケンスをマージするメソッド、4つのシーケンスをマージするメソッドと、いくつか作成しておくと便利です。