Loading [MathJax]/extensions/tex2jax.js

2012年11月25日日曜日

C# デリゲート5 (その他のジェネリックデリゲート)

ジェネリックデリゲートってなに?
Actionのこと。
ただし、Action以外にももう少しある。

Predicate<T>
これは引数を1つもち、戻り値がboolのデリゲート型。
Func<T、TResult>
引数を0~16個まで持ち、戻り値がTResult型のデリゲート型。

2012年11月24日土曜日

C# デリゲート4 (ラムダ式ってなに?)C#

ラムダ式ってなに?
匿名メソッドをもう少し簡単なかたちで書くことができる機能。
() ⇒ {} みたいな感じで書ける。
どうやって使うの?
  1. delegate()  
  2. {  
  3. }  
  1. () =>  
  2. {  
  3. }  
で置き換えるように使う。
サンプル
前回までのももたろうのサンプルで匿名メソッドにラムダ式を導入。
  1. static void Main(string[] args)  
  2. {  
  3.     // 3人をお供に加える。  
  4.     Dog dog = new Dog();  
  5.     Monkey monkey = new Monkey();  
  6.     Kiji kiji = new Kiji();  
  7.   
  8.     // 攻撃の作戦をたてる  
  9.     Action[] attacks = new Action[4];  
  10.     attacks[0] = dog.Attack;  
  11.     attacks[1] = monkey.Attack;  
  12.     //attacks[2] = delegate()       // 匿名メソッドを  
  13.     attacks[2] = () =>              // ラムダ式で書き換え  
  14.     {   
  15.         //ここで関数を直に定義している。  
  16.         Console.WriteLine("ここで一休み");   
  17.     };  
  18.     attacks[3] = kiji.Attack;  
  19.   
  20.     // 攻撃する  
  21.     for (int i = 0; i < attacks.Length; i++ )  
  22.     {  
  23.         attacks[i]();  
  24.     }  
  25.   
  26.     Console.ReadLine();  
  27. }  
備考
・ラムダ式の表現の仕方はいっぱいある。
  1. () =>  {式}  
  2. (変数) => {式}  
  3. 変数 => {式}  // ()を省略  
  4. 変数 => 式  // {}を省略  

C# デリゲート3 (匿名メソッドってなに?)

匿名メソッドってなに?
デリゲート型の変数に渡す関数をその場で定義するような感じ。
サンプル
前回までの例で説明すると、犬、猿に攻撃した後に一休みして、きじに攻撃させようというときに、 一休みを匿名メソッドで書いてみる。
  1. static void Main(string[] args)  
  2. {  
  3.     // 3人をお供に加える。  
  4.     Dog dog = new Dog();  
  5.     Monkey monkey = new Monkey();  
  6.     Kiji kiji = new Kiji();  
  7.   
  8.     // 攻撃の作戦をたてる  
  9.     //Attack[] attacks = new Attack[3];  
  10.     Action[] attacks = new Action[4];  
  11.     attacks[0] = dog.Attack;  
  12.     attacks[1] = monkey.Attack;  
  13.     attacks[2] = delegate()                //★匿名メソッド★  
  14.     {   
  15.         //ここで関数を直に定義している。  
  16.         Console.WriteLine("ここで一休み");   
  17.     };  
  18.     attacks[3] = kiji.Attack;  
  19.   
  20.     // 攻撃する  
  21.     for (int i = 0; i < attacks.Length; i++ )  
  22.     {  
  23.         attacks[i]();  
  24.     }  
  25.   
  26.     Console.ReadLine();  
  27. }  
どういうときに使うの?
よくわかってない。めんどくさいときにつかうのかな? 関数が短くて大量に必要なときとかかな?

2012年11月23日金曜日

C# デリゲート2 (Actionってなに?)

Actionってなに?
前回の説明でデリゲートを使う場合は、
  1. delegate void Attack();   
という宣言が必要とのことだったけど、実は戻り値がvoidのようなデリゲートの関数は、.Net側で準備してあるのでわざわざ宣言しなくてもよいよというような機能。
それがAction
引数はなし~16個まで対応している。(.net4だと。)
なので、戻り値がvoidで引数が17個あるような関数の場合は自分で宣言する必要がある。
Actionの使い方は?
前回からの変更点として説明すると
まず、delegete~という宣言を削除する。
で以前delegete~を使っていた部分をActionに置き換える。
これでOK
ソース
前回のももたろうのサンプルだとこんな感じで書き換えることができる。
  1. namespace MomoTaro  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             // 3人をお供に加える。  
  8.             Dog dog = new Dog();  
  9.             Monkey monkey = new Monkey();  
  10.             Kiji kiji = new Kiji();  
  11.   
  12.             // 攻撃の作戦をたてる  
  13.             //Attack[] attacks = new Attack[3]; // 不要になった  
  14.             Action[] attacks = new Action[3];  
  15.             attacks[0] = dog.Attack;  
  16.             attacks[1] = monkey.Attack;  
  17.             attacks[2] = kiji.Attack;  
  18.   
  19.             // 攻撃する  
  20.             for (int i = 0; i < attacks.Length; i++ )  
  21.             {  
  22.                 attacks[i]();  
  23.             }  
  24.   
  25.             Console.ReadLine();  
  26.         }  
  27.     }  
  28.   
  29.     // delegate void Attack();  // 不要  
  30.   
  31.     class Dog  
  32.     {  
  33.         public void Attack()  
  34.         {  
  35.             Console.WriteLine("BowWow");  
  36.         }  
  37.     }  
  38.     class Monkey  
  39.     {  
  40.         public void Attack()  
  41.         {  
  42.             Console.WriteLine("ウキー");  
  43.         }  
  44.     }  
  45.     class Kiji  
  46.     {  
  47.         public void Attack()  
  48.         {  
  49.             Console.WriteLine("ケーン");  
  50.         }  
  51.     }  
  52. }  
補足
Visual Studioの定義へ移動の機能でActionの定義を見てみると、
  1. public delegate void Action();  
と定義されていることがわかる。

2012年11月21日水曜日

C# デリゲート

デリゲートってなに?
関数を変数みたいに使いたいときに使う機能のこと。
どうやって使う?
変数みたいに使いたい関数をこんな感じで定義しておく。
  1. delegate void Attack();  
そうすると、この例でいうとAttackを型として使える。 Attack型にはAttackと引数と戻り値が一致する関数がなんでも代入できる。この例でいうと引数が0で戻り値がvoidのものを代入できる。
参考ソースの説明
犬、猿、キジに攻撃させるというソースを考えてみました。 Attack型の配列を作ってそこにそれぞれのAttackを代入しておき、最後に使うということをしてます。
コード
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         // 3人をお供に加える。  
  6.         Dog dog = new Dog();  
  7.         Monkey monkey = new Monkey();  
  8.         Kiji kiji = new Kiji();  
  9.   
  10.         // 攻撃の作戦をたてる  
  11.         Attack[] attacks = new Attack[3];  
  12.         attacks[0] = dog.Attack;  
  13.         attacks[1] = monkey.Attack;  
  14.         attacks[2] = kiji.Attack;  
  15.   
  16.         // 攻撃する  
  17.         for (int i = 0; i < attacks.Length; i++ )  
  18.         {  
  19.             attacks[i]();  
  20.         }  
  21.   
  22.         Console.ReadLine();  
  23.     }  
  24. }  
  25.   
  26. delegate void Attack();  
  27.   
  28. class Dog  
  29. {  
  30.     public void Attack()  
  31.     {  
  32.         Console.WriteLine("BowWow");  
  33.     }  
  34. }  
  35. class Monkey  
  36. {  
  37.     public void Attack()  
  38.     {  
  39.         Console.WriteLine("ウキー");  
  40.     }  
  41. }  
  42. class Kiji  
  43. {  
  44.     public void Attack()  
  45.     {  
  46.         Console.WriteLine("ケーン");  
  47.     }  
  48. }  

2012年11月13日火曜日

c# 修飾子 new overrideの違い

やりたいこと
継承したときのメソッドにつける修飾子にnewとoverrideがあるけど、その違いについてまとめてみる。 現状わかっていることだけ.
準備
猫クラスと猫王クラスを準備する。まずは修飾子をつけない。
  1. class Cat  
  2. {  
  3.     public void Cry()  
  4.     {  
  5.         Console.WriteLine("にゃお~");  
  6.     }  
  7. }  
  8.   
  9. class CatKing : Cat  
  10. {  
  11.     public void Cry()  
  12.     {  
  13.         Console.WriteLine("にゃお~猫王だぞ~");  
  14.     }  
  15. }  
そうすると警告はでるが、コンパイルは通る。警告はnewを使用してください。というような内容。
newの場合
基底クラスの型に代入すると、基底クラスのメソッドが呼び出される。
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         Cat tama = new CatKing();  
  6.         tama.Cry();  
  7.   
  8.         Console.ReadLine();  
  9.     }  
  10. }  
  11.   
  12. class CatKing : Cat  
  13. {  
  14.     public new void Cry()  
  15.     {  
  16.         Console.WriteLine("にゃお~猫王だぞ~");  
  17.     }  
  18. }  
  19.   
  20. class Cat  
  21. {  
  22.     public void Cry()  
  23.     {  
  24.         Console.WriteLine("にゃお~");  
  25.     }  
  26. }  
結果は「にやお~」になる。
overrideの場合
基底クラスの型に代入しても、派生クラスのメソッドが呼び出される。
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         Cat tama = new CatKing();  
  6.         tama.Cry();  
  7.   
  8.         Console.ReadLine();  
  9.     }  
  10. }  
  11.   
  12. class CatKing : Cat  
  13. {  
  14.     public override void Cry()  
  15.     {  
  16.         Console.WriteLine("にゃお~猫王だぞ~");  
  17.     }  
  18. }  
  19.   
  20. class Cat  
  21. {  
  22.     public virtual void Cry()  
  23.     {  
  24.         Console.WriteLine("にゃお~");  
  25.     }  
  26. }  
結果は「にゃお~猫王だぞ~」になる。

2012年11月7日水曜日

[書籍]プログラミングC# を読んで

プログラミングC# を購入したので、読んで気づいた点などについて、書いていこうかなぁと思ってます。随時更新予定。


めんどくさいので3章から読み始めました。
3章 クラスと構造体によるアイデアの抽象化
・パスカル記法...GetString
型(クラスも型)/プロパティ/メソッドに使う
キャメル記法...bigCat
変数/フィールドとかに使う
・MSDNには命名規則を含むいろいろなガイドラインがある。
http://msdn.microsoft.com/ja-jp/library/ms229042(v=vs.100).aspx
・DRY・・・Don't Repeat yourself(自分で繰り返すな。)
・プロパティ : get/setを持つメンバ変数みたいなもの。
・フィールド : いつものメンバ変数。
・自動実装プロパティとは?
いままでこんな感じで書かなければいけなかったコード(C#3より前)
  1. private string myName;  
  2. public string MyName  
  3. {  
  4.     get  
  5.     {  
  6.         return myName;  
  7.     }  
  8.     set  
  9.     {  
  10.         myName = value;  
  11.     }  
  12. }  
を、こんな感じで省略できるようになったこと。
  1. public string MyName  
  2. {  
  3.     get;  
  4.     set;  
  5. }  
C#コンパイラは、内部的には前者のようなコードを作ってるので、実装者からは見えないけど、プロパティに対応するフィールドが内部的には存在しているとのこと。

・読み取り専用フィールドとは?
最初に一回だけ(コンストラクタでだけ)書き込みが可能なフィールドのこと。
例えば猫クラスの名前のように、一度変更したら変えないようなフィールドに使用する。開発中に誤って名前を書き換えたりできないようにする意味があるとのこと。
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         cat tama = new cat("タマ");  
  6.         tama.SayName();  
  7.         Console.ReadKey();  
  8.     }  
  9. }  
  10.   
  11. class cat  
  12. {  
  13.     //読み取り専用フィールド  
  14.     private readonly string name;  
  15.   
  16.     public cat(string newName)  
  17.     {  
  18.         name = newName;  
  19.     }  
  20.   
  21.     public void SayName()  
  22.     {  
  23.         //name = "にゃんこ";  // ここを有効にするとコンパイルエラーになる。  
  24.         Console.WriteLine(name + "です。");  
  25.     }  
  26. }  
・クラスは値でなく参照型なので、代入しても実態は一つ。コピーされない。
  1. cat tama = new cat("タマ");  
  2. tama.Age = 3;  
  3. cat tama2 = tama;  // コピーはされない。tama2もtamaも同一。  
  4. tama2.Age = 4;  
とすると、tamaもtama2も4歳になる。
・参照型はヒープメモリに記録される。値型はいつもスタックに記録されるわけではない?(訳者が悪いのかどっちともとれるような書き方に...)
例えばクラスが持っているフィールドはヒープに作られる。

・構造体で既定のコンストラクタを提供しないでくださいとは?
MSDNの構造体のデザインでそういうことが書いてあるけど、どういう意味?と思ってました。その答えがとても丁寧に解説してあり、ようはデフォルトコンストラクタを独自に実装できないという理由とのこと。本にはもっと詳しく書いてある。
・フィールドだけの構造体の場合は、上記の内容に従ってデフォルトコンストラクタを書かなければ問題なしでこんな風に書ける。
  1. struct position  
  2. {  
  3.     public position(int x, int y, int z)  
  4.     {  
  5.         m_x = x;  
  6.         m_y = y;  
  7.         m_z = z;  
  8.     }  
  9.     public int m_x;  
  10.     public int m_y;  
  11.     public int m_z;  
  12. }  
・なんだけどプロパティをもつ構造体の場合は、また制約があり、こういう風に書くとコンパイルエラーが発生する。デフォルトコンストラクタを呼ぶ前にメソッドを呼び出すとだめという制約がある。
  1. struct position  
  2. {  
  3.     public position(int x, int y, int z)  
  4.     {  
  5.         X = x;  
  6.         Y = y;  
  7.         Z = z;  
  8.     }  
  9.     public int X { get; set; }  
  10.     public int Y { get; set; }  
  11.     public int Z { get; set; }  
  12. }  
で、これに対応する場合はこうすればい。
  1. struct position  
  2. {  
  3.     public position(int x, int y, int z)  
  4.         :this()  // デフォルトコンストラクタを呼ぶ。  
  5.     {  
  6.         X = x;  
  7.         Y = y;  
  8.         Z = z;  
  9.     }  
  10.     public int X { get; set; }  
  11.     public int Y { get; set; }  
  12.     public int Z { get; set; }  
  13. }  
・C#4からは省略可能な引数というのがある。引数の数だけことなるようなオーバーロードをするときの代替として使える。型がちがうオーバーロードの代わりにはならないので、オーバーロードがいらなくなるわけではないと思う。 ・オブジェクト初期化子とは? newするときにプロパティを設定できる機能。コンストラクタとの使い分けが難しそう。。。
4章 拡張性とポリモーフィズム
・アソシエーションとは?
車と運転手
・集約(アグリゲート)とは?
消防車と着脱可能なホース(has-a)
・コンポジションとは?
はしご車とはしご(contains-a)
・継承とは?
消防署長と消防士(is-a)
・ポリモーフィズムとは?
消防署長クラスを消防署長と消防士の両方で使えるということ?こんなだったけ?
・リスコフの置換原則とは?
派生クラスは基底クラスに置き換えて使用できなきゃいけないよということ。
メソッドをオーバーライドしたらもうだめなのかな?
・継承するときのメソッドの修飾子newとoverrideは何が違うの?
別途まとめる。
・protectedってなに?
基底クラスのメンバなどにつける修飾子で、これをつけると派生クラスからだけは使えるようになる。publicとprivateのあいだぐらいのもの。
・internalってなに?
これをつけると別のライブラリから使えなくなる。あまり使用されてないみたいだけど、使ったほうがよいのだとか。
・sealedってなに?
これをつけると、派生できなくなる。派生させたくないクラスにはこれをつけとくとよい。
・抽象クラスのなまえは~baseにしたほうがよい。
・すべての型はObjectの派生である。(intとかもすべてのclassもobjectの派生)
・ボックス化ってなに?
objectがたの変数に値を代入すること。(とても重い)
・ボックス化の解除ってなに?
object型の変数を別の型の変数に代入すること。(こちらも重いがボックス化よりは軽い)
・C#では多重継承がないかわりにインタフェースがある。
・インタフェースって何?
イメージとしては抽象クラスのような感じ。使い分けはよくわからないけど、インタフェースの方が使いやすいのかな?
インタフェースは多重継承みたいなことができる。

5章 デリゲートによる関数合成
・デリゲートとは「単に、任意の関数をいくつかのプロパティに登録し、順番に呼び出すオブジェクトでしかない」とのこと。
・5-1まで読んだが、なんだがしっくりこず。http://ufcpp.net/study/csharp/sp_delegate.html こちらのほうが参考になった。関数を型として扱うような感じとのこと。deleget ~と宣言するとそれと同じ引数と戻り値をもった関数を同じ型として扱うことができる。(別途まとめたい) ・戻り値を持たないデリゲートの場合は、型を宣言しなjくてもAction<引数>というもので代用できる。
・デリゲート型の変数をプロパティとすることもできる。その場合、関数をgetしたり、setしたりできる。
・匿名メソッドは親の関数で定義されている変数にもアクセスできる。
・その他は別の記事にまとめた。
6章 エラー処理
・エラーが起きたときの対処策としては、一般的には次の方法がある。
1.気にせず継続する
2.対処する(まるめるとかそんな感じ。)
3.エラー値で処理する
4.停止する。

で、1だと期待した結果にならなかったり、プログラムが突然落ちたりなんかするのでNG
2だといい場合もあるけど、ダメな場合もある。
※詳細は書籍で。
3だと正常系と同じぐらい異常系のためのコードが必要になり、それ以外にもいろいろ大変とのこと。
4については説明がないけど、なので、例外を使いましょうという感じ。
・例外(excepttion)を使うメリットは?
 エラー処理が不要になる。(エラーコードを伝搬させるよくある処理)
 (⇒サブサブサブサブ関数で、エラーが起きたときに例外を投げれば、一番上まで届くので)
 ということで、エラー系にひとまず頭をなやませなくてもよい。
 デバッカを使っていれば、エラーが発生した場所(exception)した場所が明確にわかる。
・暗黙的な再スローって何?
throw;でもう一回スローすること。
この方法だと呼び出し履歴の情報がのこるとのこと。
・明示的な再スローってなに?
throw 例外オブジェクト;でスローしなおすこと
この方法だと呼び出し履歴の情報が再スローしなおしたところからになるとのこと。
再スローしなおすと、元の例外は再スローした例外のinnerExceptionプロパティとして記録される。
・カスタムの例外はできるだけ使わないほうがよい。

7章 配列とリスト
・配列にはFindAllというメソッドがある。便利そう。
・多次元配列には、配列の配列 int[][]と
・四角形配列 int[ , ]がある。