2014年7月28日月曜日

C#応用 – LINQプログラミング 10 (Exercise1)



さて、LINQプログラミングの第10回は

Exercise1 拡張メソッドとラムダ式を

見ていく。



IEnumerableに対しての検索機能とジェネリックコレクションの利用方法を習得する。

まずは、Ex01.slnのソリューションファイルを開くと

ソリューションエクスプローラのProgram.csはこの様になっている。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ex01
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, string> dicLines = new Dictionary<string, string>();
            #region dictionaryの初期化
            dicLines.Add("A", "都営浅草線");
            dicLines.Add("I", "都営三田線");
            dicLines.Add("S", "都営新宿線");
            dicLines.Add("E", "都営大江戸線");
            dicLines.Add("G", "東京メトロ銀座線");
            dicLines.Add("M", "東京メトロ丸ノ内線");
            dicLines.Add("m", "東京メトロ丸ノ内線方南町支線");
            dicLines.Add("H", "東京メトロ日比谷線");
            dicLines.Add("T", "東京メトロ東西線");
            dicLines.Add("C", "東京メトロ千代田線");
            dicLines.Add("Y", "東京メトロ有楽町線");
            dicLines.Add("Z", "東京メトロ半蔵門線");
            dicLines.Add("N", "東京メトロ南北線");
            dicLines.Add("F", "東京メトロ副都心線");
            #endregion

            //ここに追加(その2)
            foreach (var item in dicLines.MyFindAll("東","ノ"))
            {
                Console.WriteLine("{0}\t{1}", item.Key, item.Value);
            }

            Console.WriteLine("Hit any key...");

            Console.ReadKey();
        }
    }

    static class MyDicExtention
    {
        /// <summary>
        /// Dictionaryの独自拡張メソッド
        /// </summary>
        /// <param name="dic">対象となるDictionary(Key=String,Value=String)</param>
        /// <param name="containsValue">Valueに含むべき文字列</param>
        /// <param name="containsValue2">Valueに含むべき文字列(その2)</param>
        /// <returns>絞り込まれた結果の列挙</returns>
        public static IEnumerable<KeyValuePair<string, string>> MyFindAll
                (
                this Dictionary<string, string> dic,
                string containsValue,
                string containsValue2
                )
        {
            //ここに追加(その1)
            return dic.Where(x => x.Value.Contains(containsValue)
                                &&
                                x.Value.Contains(containsValue2)
                                );
        }
    }
}

自分で追加する部分は、緑のコメントで ここに追加 となっている下の

青文字部分である。

実行結果は次の通り。




単に実行しただけでは、

それが、検索結果だと分かりにくい。


解説
最初に追加した部分(その1)は Dictionary の拡張メソッド「MyFindAll」の実装を

定義している。「MyFindAll」内では Dictionary に対して、引数で与えられた2つの文字列を

Value に含む要素で絞込みを行い、結果を返却している。

次に追加した部分(その2)では、上記 MyFindAll を呼び出して結果を取得し、

Consoleに出力を行う。


参考
その1で追加したソースコードを以下のように変更しても、同じ結果が取得できる。

foreach (var item in dic)
{
    if (item.Value.Contains(containsValue) &&
        item.Value.Contains(containsValue2))
    {
        yield return item;
    }
}

もちろん、実行結果は同じである。



今日の名言
幸福の秘訣は、自分がやりたいことをするのではなく、自分がやるべきことを
好きになることだ。
                               ジェイムズ・M・バリー

我々は幸福も不幸も大げさに考えすぎている。自分で考えていることほど
幸福でもないし、かといって決して不幸でもない。
                               オレン・ド・バルザック

黄金のように貴重な時間の瞬間の機会を大いに利用し、自分の手に届く限りの
良いものをつかみ取ることは、人生における偉大なる芸術行為だと言える。
                               サミュエル・ジョンソン

環境だけで人間の幸不幸が決まるのではないことは、明らかだ。幸福だとか
不幸だとかいう気持ちの在り方は、こうした環境をどのように受け止めるかに
よって決定される。「天国は心の中にある」とはキリストの言葉だが、
地獄もまた同様である。
                               デール・カーネギー


2014年7月11日金曜日

C#応用 – LINQプログラミング 9




さて、LINQプログラミングの第9回

今回は、拡張メソッドについてである。




拡張メソッド
既に存在するクラスに機能を付加する。

var query = any.Where(x => myInclude(x)).Select(x => new { StationName = x });

foreach(var item in query)
{
    Console.WriteLine(item.StationName);
}


拡張メソッド(1)
既に存在しているクラス(コンパイル済みのものを含む)に対して
メソッドの追加が行える機能である。

たとえば、以下のようなものがある。
using System;

namespace MIC
{
    public static class StringExtension
    {
        // stringに対しての拡張メソッドである
        public static string AddABC(this string s)
        {
            return s + "ABC";
        }
    }
}


拡張メソッド(2)
使用方法は次のようになる。

using MIC;    // MICの拡張メソッドを使用するため

中略

string name = "マイクロソフト";
Console.WriteLine("{0}", name.AddABC());


拡張メソッドの記述方法
 作成の条件は次の通り。

  • staticメソッドである
  • staticクラスに記述されている
  • 第一パラメータの先頭にthisキーワードが記述されている
  • 第一パラメータの型が追加先となる型である  


拡張メソッドの特性
 拡張メソッドは以下の特徴がある。

  • 拡張メソッドの記述先をusingされなければ拡張されない
  • 同じ名前の拡張メソッドをもつ
    異なる名前空間を使用するのは不可
    例:同名の拡張メソッド「Ex」を持つ名前空間「NS1」と「NS2」を同時には使用できない
  • usingされるとsealedされたクラスも拡張可能
  • 元となる型のprivateやprotectedのメンバにはアクセスできない
  • 拡張メソッドは元のクラスの振る舞いは変更できない


追加された拡張メソッド
 List<T>のメンバを確認した
 
 ⇒実はList<T>ではなく、IEnumerable<T>の拡張メソッド
     
 ⇒つまり、これらの拡張メソッドは列挙に対して作用する機能

 実装はSystem.Linq.Enumerableクラス




ソースコード内の構文で

F1を押すと簡単にWebのマニュアルを

参照できるので非常に便利である。




今日の名言
人間にとって可能なあらゆる真に健康な楽しみを味わうことは、人間が初めて
この世に創造された時以来、可能であったし今でも可能である。そしてこれらの
楽しみが得られるのは主に心が平安である時である。麦が成長するのを見守る、
畑で鋤や鍬をふるって息を切らす、本を読み、考える、愛する、望む、神に祈る
これらはすべて人間を幸福にする事柄である。時折疲れ果てた王や虐げられた
奴隷が、この世の真の王国がどこにあるのかを見出し、庭の畑の一うねに
無限で真の領土を建設することがある。
                               ジョン・ラスキン

私の言い方は、行く手を遮る不幸に対してことごとく頭を下げろと主張している
ように聞こえるだろうか?断じてそうではない!それでは単なる運命論ではないか。
事態を好転させるチャンスがある限り闘うべきだ!けれども、常識で判断して
もはや万事休すとなれば、「悪あがきをしたり逆転を望んだりしない」ことが
正気の沙汰というものだ。
                               デール・カーネギー



2014年7月1日火曜日

C#応用 – LINQプログラミング 8



さて、C#応用 LINQプログラミング

第8回である。


今回は、型とプロパティの説明である。



型・プロパティとLINQ
式の中で実行させたい処理を記述する際に必要である。

var query = ary.Where(x => myInclude(x)).Select( x => new { StationName = x } )

foreach(var item in query)
{
    Console.WriteLine(item.StationName);
}

var query の部分では型推論(後述)を行っている。

new { StationName = x } は初期化子で匿名型(後述)である。


自動実装プロパティ
    private string = _prop1;
    public string Prop1
    {
        get { return _prop1; }
        set { _prop1 = value; }
    }

上記と同様のことが下記で実現する。

    public string Prop1 { get; set; }

また、set のみ private にすることも可能である。

    public string Prop1 { get; private set; }


型推論
LINQを実現するにあたり、Saftyな型システムを維持しつつ可読性やコーディングへの

負担を減少させるための仕組みが必要となった。 ちなみに、読み方は 「バル」らしい。

    var a = 2;       // aはint
    var b = "abc";         // bはstring
    var c = (int) 1;         // cはint
    var d = new Hoge();  // dはHogeクラスのインスタンス

使用時の注意点
セットされる値からコンパイラが自動的に型を推論するため、変数への初期化が必須である。

数値や文字はリテラルもしくは書式により判定される。

var キーワードはローカルスコープのみ利用できる。


オブジェクト初期化子
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    var p new Person() { Name = "舞黒 太郎", Age = 20 };

公開されているフィールド・プロパティにコンストラクタを呼び出すことなく

値を割り当てることができる。

ただし、Null許容型(Nullable)には利用できない。


コレクション初期化子
    var plist = new List<Person>
        {
            new Person() { Name = "舞黒 太郎", Age = 30 },
            new Person() { Name = "大手 花子", Age = 25 }
        };

IEnumerableを実装するコレクションクラスを初期化する際に、

1つ以上の要素を初期化子として指定できる。

Addメソッドを複数回呼び出さなくともコンパイラによって呼び出しが追加される。


匿名型(Anonymous Type)
型推論、オブジェクト初期化子を利用し、型(クラス)を定義しないままの

オブジェクトを生成できる。

    var p = new { Name = "舞黒 太郎", Age = 30 };

    Console.WriteLine( "{0} 年齢は {1}", p.Name, p.Age);

これらは暗黙的に以下のことを行っている。
 ▻ 読み出しのみのプロパティとreadonlyのprivateフィールドを持つクラスの
  インスタンスを生成(つまり値は初期値から不変となる)

 ▻ 各プロパティ・フィールドの型はオブジェクト初期化子で初期化される値から推論される。

 ▻ クラスの定義そのものは公開されないため、匿名となる

 ▻ プロパティの並び順は厳格に保存される

上記のことから、var キーワードの利用が必須である。


匿名型の内部表現
以下の表現は
    var p = new { Name = "舞黒 太郎", Age = 30 };

コンパイラでは近似となる以下のコードに置き換わる。

  internal sealed class 匿名クラス<TName, TAge> {
        private readonly TName    __name;
        private readonly TAge       __age;

        public TName Name         { get { return __name; } }
        public TAge Age              { get { return __age;    } }
    }

    var p = new 匿名クラス<string, int> { Name = "舞黒 太郎", Age = 30 };


ラムダ式(2)
ラムダ式とは式とステートメントを含めることができる匿名関数であり、
デリゲート型または式ツリー型を作成するために使用できる。

・デリゲート
    delegate int dd(int i)
    dd myFunc = x => x * x;    // xがint型であることがコンパイラにより推論されている
    int v = myFunc(5);

・式ツリー
    Expression<dd> = x => x * x;


今日の名言
賽が投げられた自分の運命に自分自身を適応させよ。運命の女神が、
ともに生きるように定めた仲間を愛せよ。
                               マルクス・アウレリウス

ほとんどたいていの物事は、何の疑いもなく朗らかに受け入れれば、
様相を新たにする。
                               ヘンリー・S・ハスキンズ

この世であなたの主な目標は幸福である。幸福は健康とか名声には
左右されない。もっとも健康は幸福に大いに関係があるが、しかし幸福に
なれるかどうかを大きく左右するものがたった一つある。それは物の考え方だ!
自分の欲しいものが手に入らなければ、自分が今持っているものに対して
感謝することだ。些細なものが手に入らないからと愚痴を言わないで、
自分には感謝すべき大きなものがあることを常に考えるべきだ。
                               デール・カーネギー

真に人間らしい結びつきを得るには、人類が昔からやってきた通りにすれば
よい。神から与えられた我々の境遇、幸運の星のもと、我が祖国に
生まれた幸せを、スポーツマンのような態度で快く受け入れることだ。
                               ギルバート・キース・チェスタートン