FROM ME TO YOU

oh my bizarre life !!

Visual C# 2013 パーフェクトマスター 6章 コレクションとジェネリック

自分の不明点をとりまとめ。理解できているところは割愛。

配列とコレクション

1次元配列

    int a = new int[10];
    a[4] = 80;

二次元配列

    int a = new int[3,10];
    a[1,4] = 10;

コレクションクラス

ArratListクラスは動的に配列数を変更できる。 コレクションとは複数のオブジェクトをまとめて管理する機能。

            ArrayList col = new ArrayList();
            col.Add("hogehoge");
            col.Add("fugafuga");
            Console.WriteLine(col[1]);

ArrayListクラスのaddはobject型のためキャストが必要な場合がある

            ArrayList col = new ArrayList();
            col.Add(100);
            string text = "hogehoge";
            col[0] = text;
            text = col[0];
            /// 'object' を 'string' に暗黙的に変換できません。
            /// 明示的な変換が存在します。(cast が不足していないかどうかを確認してください)
            /// text = Convert.ToString(col[0]);

ジェネリック

ジェネリックは様々な型に対応するために型をパラメータとして指定し、その型に対応したクラスやメソッドを生成する機能。

Listジェネリッククラス

Listジェネリッククラスではパラメータリストにデータ型を記述することでリストで扱うデータ型が指定できる。 ArryListクラスではキャストが必要だったためListジェネリッククラスの方がパフォーマンス上優れている。

            List<string> list = new List<string>();
            list.Add("100"); /// list.Add(100)ならエラー
            string text = "hogehoge";
            list[0] = text;
            text = list[0];
            Console.WriteLine(list[0]);

Dictionaryクラス

キーと値をペアで管理します

        static void Main(string[] args)
        {
            var obj = new Dictionary<string, int>();
            obj.Add("hogehoge", 10);
            obj.Add("fugafuga", 20);
            Disp(obj);
        }

        static void Disp(Dictionary<string, int> t)
        {
            foreach (var item in t.Keys)
            {
                Console.WriteLine(item, t[item]);
            }

        }

型パラメータを持つクラス

同じ配列を繰り返し使える場合に型毎に配列を宣言せず、型パラメータを使って単一化できる。

namespace ConsoleApplication1
{

    public class ListTest<T>        /// Tは型パラメータ。コンストラクタで指定。
    {
        T[] list = new T[100];      /// Tの型の配列を100個宣言
        int add;                    /// 配列のインデックス値

        public void AddItem(T item) /// 配列格納用のメソッド
        {
            list[add++] = item;     /// add++で呼び出し毎に配列を追加して値を格納
        }

        public T this[int index]    /// インデクサ
        {
            get
            {
                return list[index]; /// indexを指定して呼び出し
            }
            set
            {
                list[index] = value;/// 値をセット
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ListTest<string> list = new ListTest<string>();

            list.AddItem("1番目");
            list.AddItem("2番目");

            string str1 = list[0];
            Console.WriteLine(str1);

            ListTest<DateTime> dtlist = new ListTest<DateTime>();

            dtlist.AddItem(DateTime.Today);

            DateTime today = dtlist[0];
            Console.WriteLine(today);
        }
    }
}

複数の型パラメータを持つクラス

    class test<T1, T2>
    {
        public T1 val1 { get; set; }
        public T2 val2 { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var a = new test<string, int>();
            var b = new test<int, string>();

            a.val1 = "abc";
            a.val2 = 100;
            b.val1 = 200;
            b.val2 = "xyz";

            Console.WriteLine(a.val1 + "," + a.val2);
            Console.WriteLine(b.val1 + "," + b.val2);
        }
    }

 

ジェネリックメソッド

型パラメータをメソッドに対して設定してみる

    class Program
    {
        static void Disp<T>(T p)
        {
            Console.WriteLine(p);
        }

        static void Main(string[] args)
        {
            Disp<int>(500);
            Disp<string>("hogehoge");

            Disp(500); /// 型指定は省略可
            Disp("fugafuga");
        }
    }

型パラメーターの命名ガイドライン

型パラメーターは1文字で指定。「T」 複数の型パラメーターを持つ場合はわかりやすく、先頭にTをつける。「TInput,TOutput」等。

イテレータ

クラス内での繰り返し処理を行うforeachステートメントはコードが複雑かつ冗長になる場合がある。 yieldステートメントを利用して簡略化が可能。

    class Program
    {
        public static IEnumerable MethodShow()
        {
            yield return "hogehoge";
            yield return "fugafuga";
            yield return "piyopiyo";
        }

        static void Main(string[] args)
        {
            foreach(string val in Program.MethodShow())
            {
                Console.WriteLine(val);
            }
        }
    }

疑問点

イテレータ

「foreachステートメントはコードが複雑かつ冗長になる場合があるのでイテレーターのyieldステートメントを使う」とあるが、サンプルコードを見る限りforeach文自体はあまり簡略化されてない気がする。 foreachでループするオブジェクトを事前に用意するのじゃなく、その都度メソッドで宣言できるということ?