C# オブジェクト初期化子でプロパティのプロパティを初期化

C#でオブジェクト初期化子という構文があります。
オブジェクトの作成時にアクセス可能なプロパティやフィールドに値を割り当てるもので、
例えば次のように書きます。

var person = new Person() {
    Name = "Taro",
    Id = 1,
};

これは以下と同等です。

var person = new Person();
person.Name = "Taro";
person.Id = 1;

メリットは初期化の内容が1箇所に集まることで、
初期化中に間違って別の処理が混入することが無いことです。
なので積極的に利用すべきですね。

初期化できるのはアクセス可能なメンバーに限定されるので、
例えば以下のケースはコンパイルエラーとなります。

var parent = new Parent() {
    Person = new Person(),  //Person プロパティはsetできないのでコンパイルエラー
};
class Parent {
    public Person Person { get; } = new Person();
}

class Person {
    public string Name { get; set; }  //プロパティ
    public int Id;  //フィールド
    public List<int> RelatedId { get; }

    //コンストラクタ
    public Person() {
       RelatedId = new List<int>() { 1 }; //要素"1"で初期化
    }
}

Parentオブジェクト初期化子内で、
Personプロパティのプロパティを設定したい場合は以下のように書きます。

var parent = new Parent() {
    Person = { Name = "Taro", Id = 1 }
};

ではList<int>に値を指定した場合はどうなるでしょうか?

var parent = new Parent() {
    Person = { Name = "Taro", Id = 1, RelatedId = {10, 20}}
};

RelatedIdはコンストラクタで初期化された値に値が追加され、
この場合、要素が{1, 10, 20}の要素数3のコレクションとなるようです。
あまり使いどころは無いかもしれませんが、覚えておくとどこかで役に立つかもしれません。

PostgreSQL

今進めている案件で初めてPostgreSQLを使用しました。

いつもはSQLServerを使用することが多いので、下調べから始めましたがなんとか使用できるようになりました。
管理ソフトはHeidiSQLを使用しています。特に問題なしです。
C#のライブラリはEntityFramework6.Npgsqlを使用しています。EntityFrameworkはシンプルで良いですね。

思っていたより敷居が低くで良かった。

プログラムの勉強について

こんにちはmtjです。

プログラムの勉強について プログラムを勉強しようとして本を読むと大体挫折してしまうと思います。
IF文、For文という文章を読んだとしても分岐、繰り返し処理をするものだとわかってもそれを使う場面が想像できないと只詰め込むだけになってしまうためです。

プログラムの勉強はインプットとアウトプットが合わさって初めて物になると自分は思います。
繰り返し、分岐の話もそれを元に何が作れるかを考えると勉強も捗ると思います。

例えば繰り返しで簡単な時計を作ろうとします。
Forループでは固定回数しか動かせないので時計は途中で止まってしまいます。
そこでWhile等の無限ループを覚え、無限ループをするとメインスレッドが止まってしまうので別スレッドの動き等を学んだりします。

上記のように何かを作ろうとすれば付随していろいろな事も勉強できます。

プログラムを教える人達(主に学校で)がそういう意識を持つことでもっとプログラムの面白さ、簡単さを伝えられるのではないのかなと思いました。
プログラムの難しさはプログラム自体じゃなく勉強の仕方自体にあると自分は思います。

Visiual Studioの右クリック時メニューに項目を追加する方法

先日、Visual Studioでコードエディタ上を右クリックした際のメニュー*に、
上部メニュー内の項目(ビルドなど)があると良いな~と思うことがありました。
* コンテキストメニューと言うそうですね

少し調べてみたら方法がわかったので、備忘録も兼ねて以下に記載します。

1. 上部メニューのツールからカスタマイズを開く

2. カスタマイズのコマンドタブで
2-1. コンテキストメニュー:エディタコンテキストメニュー|コードウィンドウを選択

2-2. コマンドの追加を開き、目的のコマンドを追加

以上の手順により、コードエディタ上で右クリックした際のメニューに目的の項目(コマンド)を追加できました。

頻繁に使うわけではないけれども上部メニューから一々実行するのは手間な場合に、
ショートカットキーと違って覚えておく必要のない、
今回のコンテキストメニューへの追加が便利なのかな、と思います。

参考にさせていただいたのは以下のサイトになります。
ありがとうございました。
Sunday Programmer’s Report: Visual Studio のコンテキストメニューに「Blend で開く」を追加する

ソフトウェアの完成

製作しているソフトウェアが完成すると嬉しいものです。
でも完成のタイミングとはいつなのでしょうか?
実装が全て完了して、
仕様を満たしているか、動作は問題無いか等の確認を行い、
全て合格した場合に完成となります。

ただ動作テストの時にいろいろ気付くこともあり、
そのときに「この部分は使い勝手が悪い」「もっとこうしたほうが良い」など、
特にUI(ユーザーインターフェース)周りで改善案が浮上します。
私の場合はこの時点で挙がった改善案をtodoとして、
それらを解決した時点で完成としています。

デザインやUIの部分は、想定する使い方が変わると、
「使いやすさ」を実現する方法も変わってしまいます。
これらの全て実装すると開発期間やコストをオーバーしてしまいますので、
まずは普通の使い方で不便を感じない実装が重要だと考えています。

それでも「期待以上だった」とお客様に言って頂けるような、
そんなソフトウェアを目指しています。

PLINQ(Parallel LINQ)の結果の要素順

以前にPLINQ(Parallel LINQ)の実行速度を調査し、簡単にLINQを並列化して速度改善できることが分かりました。

しかし、PLINQを使用した場合、結果の要素順はどうなるのでしょう?
本来なら元の要素順に取り出したいのですが、並列化されているので順不同なのでしょうか?
調べてみた結果、PLINQを使用しても元の順番通りに要素が取得できました。すばらしい。

詳しくは調査していませんが、PLINQのメソッドの戻り値はParallelQuery型になっており、たぶんこのクラスか、これを継承したQueryOperatorクラスあたりでうまいこと取出し順序を調整しているのでしょう。

プログラマーの必要性

こんにちはmtjです。

現代の小さくて安いAIカメラ等を見て思いますが 最近はプログラムレスで面白い機能があるサービス、商品が大量にあります。
その商品自体はプログラムで組まれておりますが 使う側はプログラムがほとんど必要ありません。

昔に比べてプログラムですべて作るより、プログラムで使える面白いサービス、商品にアンテナを貼り
それらを上手に使用する能力のほうが現代では必要ではないかと思います。

特にクラウドサービス類は1から作るとしたらとんでもない労力になります
作り方を知っている、想像できるまではあってもよいのですがそれらシステムを実際に作る必要がある人は一部の人でしょう。
大半の人はそれらを上手に使用する方法を覚えたほうが物になります。

今後の展示会等でもそういった物を覚えていけたら良いなと思いました。

Strategyパターン

たまの休日に一部の復習も兼ねて、”Java言語で学ぶデザインパターン入門”を亀のようなペースで読み進めています。
個人的に一番好きなパターンはStrategyパターンです。
このパターンは、インタフェースを定義してアルゴリズムを交換可能にするもので、
典型的な使いどころには、ゲームにおけるプレイヤーAI(CPUなどとも呼ばれますね)の思考ルーチンが挙げられます。
例えば、囲碁や将棋などの対戦ゲームにおいて、戦略の異なるAIをこのパターンで実装します。
以下のような形ですね。


public interface IPlayerStrategy {
    // 入力されたゲーム状態を元に行動を決定
    PlayerAction DetermineAction(GameState state);
}

public class AggressiveStrategy : IPlayerStrategy {
    public PlayerAction DetermineAction(GameState state){
        // 攻撃的な戦略に基づいて行動決定
    }
}

public class DefensiveStrategy : IPlayerStrategy {
    public PlayerAction DetermineAction(GameState state){
        // 防御的な戦略に基づいて行動決定
    }
}

public Player {
    private readonly IPlayerStrategy _strategy;

    public Player(IPlayerStrategy strategy){
        _strategy = strategy;
    }

    public PlayerAction GetNextAction(GameState state){
        return _strategy.DetermineAction(state)
    }
}

名が体を表す良いパターンだと思います。
個人の趣味ですが、典型例がゲームなのも良いですね。

実務経験はほぼないので、憶測になってしまうのですが、
実務であれば例えば、あるクラスにおいて、インスタンス生成時に決定される同一のフラグによって挙動を切り替える処理が何度も登場するような場合に、
Strategyパターンを適用できるのではないかと思っています。
インタフェースを切り、フラグのオンオフの挙動をそれぞれその具象クラスに切り出すことで、
外部のクラスには影響を及ぼさずに、フラグ毎の処理の見通しを良くできるような気がしています。

経験を積んで、パターンの使いどころを見極められるようになりたいです。

C# のコーディング規則

C# のコーディング規則
Microsoft公式ドキュメントに「C# のコーディング規則」が追加されました。
2021/5/14 の新しい内容です。

この記事のガイドラインは、サンプルおよびドキュメントを開発するために Microsoft によって使用されます。これらは、.NET ランタイムの C# コーディング スタイル ガイドラインから採用されました。それらを使用することも、ニーズに合わせて調整することもできます。 主な目的は、プロジェクト、チーム、組織、または会社のソース コード内での一貫性と読みやすさです。

とあるように、Microsoftでも使用される内容なので、
コーディング規則はこれをベースにするのが良さそうです。
フィールドはキャメルケースに_プレフィクスを付ける事が明文化されています。

  • private または internal のフィールドに名前を付ける場合は、キャメルケースを使用し、_を使用してプレフィックスを付けます。
  • ステートメント補完をサポートする IDE でこれらの名前付け規則に従う C# コードを編集するときは、「_」と入力すると、オブジェクト スコープのすべてのメンバーが表示されます。
  • なので自動実装ではないプロパティを使用する場合、
    バッキングフィールド名はプロパティ名の先頭を小文字にして_プレフィックスを付けたものになります。

    あと気になった点は、次のような点でしょうか。
    コメントは文章で書くようにという事ですね。

  • private または internal である static フィールドを使用する場合は、s_プレフィックスを使用し、スレッド静的には t_を使用します。
  • コメントのテキストはピリオドで終了します。
  • もちろん最初に書いてあるように、この規則はニーズに合わせて調整することもできますが、
    基本の規則として知っておくと良いと思います。

    PLINQ(Parallel LINQ)の実行速度

    .netのPLINQ(Parallel LINQ)による並列実行の効果がどれほどなのか理解していなかったのでテストしました。

    Select、Where、AverageをLINQとPLINQで実行し、速度を確認します。

    
    var items = Enumerable.Range(1, 100_000_000).ToArray();
    
    var sw1 = Stopwatch.StartNew();
    var results1 = items.Select(x => Math.Pow(x, 0.5)).ToArray();
    Debug.Print($"Select LINQ {sw1.Elapsed}");
    
    var sw2 = Stopwatch.StartNew();
    var results2 = items.AsParallel().Select(x => Math.Pow(x, 0.5)).ToArray();
    Debug.Print($"Select PLINQ {sw2.Elapsed}");
    
    var sw3 = Stopwatch.StartNew();
    var results3 = items.Where(x => Math.Pow(x, 0.5) >= 100).ToArray();
    Debug.Print($"Where LINQ {sw3.Elapsed}");
    
    var sw4 = Stopwatch.StartNew();
    var results4 = items.AsParallel().Where(x => Math.Pow(x, 0.5) >= 100).ToArray();
    Debug.Print($"Where PLINQ {sw4.Elapsed}");
    
    var sw5 = Stopwatch.StartNew();
    var results5 = items.Average(x => Math.Pow(x, 0.5));
    Debug.Print($"Average LINQ {sw5.Elapsed}");
    
    var sw6 = Stopwatch.StartNew();
    var results6 = items.AsParallel().Average(x => Math.Pow(x, 0.5));
    Debug.Print($"Average PLINQ {sw6.Elapsed}");
    

    結果

    
    Select LINQ 00:00:04.9831283
    Select PLINQ 00:00:01.1474103
    
    Where LINQ 00:00:04.7858871
    Where PLINQ 00:00:00.7447430
    
    Average LINQ 00:00:03.8039131
    Average PLINQ 00:00:00.3454058
    

    今回のテストプログラムの場合、4倍~11倍の速度改善になっています。
    .AsParallel()を追加するだけで、これだけの速度改善になるので、処理が遅くて困った場合にはまずPLINQを試すのが良さそうです。