Software_CS2

☆CSharp その2
(VisualC#)

┌──┐
│目次│
├──┘
│◎文法(続)
◆選択ステートメント if
◆繰り返しステートメント repeat
◆ジャンプステートメント jump
◆例外処理ステートメント excep
◆イベント event
◆排他制御 lock
◆リソース管理 using
◆マルチスレッド thread
◆メソッド method

│◎文法(続々)

◆選択ステートメント

_◇if

if ()
{

}
else if ()
{

}
else
{

}

_◇switch

switch ()
{
    case 値1:
        ブロック1
        break;
    
    。。。
    
    default:
        ブロック
        break;
}


◆繰り返しステートメント

_◇do 。。。 while

do
{

}
while();

_◇for

for(初期化式; 継続条件式; 継続処理式)
{

}

_◇foreach

foreach (型 変数名 in 配列)
{

}

※配列またはコレクション内の全要素に対して処理を行う。

_◇反復子
│ 一連のデータを特定の順序で取得するために使用するオブジェクト。
│ メソッド、演算子、getアクセサ本体として使用できる。
※IEnumerableインタフェース全体を実装しなくても、反復子を実装すれば、コンパイラがIEnumerableインタフェースのメソッドを自動的に生成し、データ構造をforeachにより走査できるようになる。
※yieldキーワードを使用して、単数または複数の戻り値を指定する。
※yield returnステートメントにより現在位置が保存され、次回、反復子が呼び出されると、この位置から実行が再開される。
※反復処理は yield break で終了する

_◇while

while (式)
{

}


◆ジャンプステートメント

_◇break
│ 繰り返しもしくはswitchステートメントで処理されるブロックの最も内側を終了させ、
│ 次のステートメントに移動する。

_◇continue
│ 繰り返しステートメントのブロックでcontinue以降を飛ばして、次の繰り返しに入る。

_◇goto
│ 制御をラベル付きステートメントに直接移動する。
│ switchステートメントのcase, defaultラベルも含まれる。

例)

    goto LOOP_EXIT;
    
    。。。
    
    LOOP_EXIT:

_◇return
│ メソッドの実行を終了し、制御を呼び出し元に戻す。戻り値がある場合、returnの後に指定する。


◆例外処理ステートメント

※例外処理に対するアプローチの考え方
A)きめ細かいアプローチ
│ 単体コードそれぞれに例外処理コードを追加
│ ⇒やりすぎると過剰な例外処理コードであふれる
│ ⇒その部分が特有の例外処理を必要とする場合にとどめるべき
B)おおまかなアプローチ
│ 他のさまざまなコードを呼ぶコード全体に対して例外処理を行う

※例外の遡及
│ コードの任意の場所で発生した例外
│ ⇒例外を処理できるcatchブロックが見つかるまでコールスタックをさかのぼる

※例外の利点
│ 例外の発生は無視できない。(エラーコードの返り値は無視できる)

_◇try-catch
│ tryブロックに例外がおきる可能性のあるステートメントを配置する。
│ 例外が発生した場合、catchブロックに制御が移る。

※catchブロックの型と変数の指定を省略する場合、カッコも省略する。
│ ⇒引数の無いcatchブロックはC++への対応でもある。
│ (C++では任意の型のオブジェクトが例外としてスローできる)
│ CLRではSystem.Exceptonの派生クラスのインスタンスにマッピングされる
│ ⇒Catchブロックで Exception オブジェクトを取得する必要がなければ省略できる
│ しかし、引数の無いcatchブロックは通常使うべきでない

※C#で例外としてスローできるのはException基底クラスから派生したクラスのみ

※catchブロックは複数あってもよい。

※try-catchを使用せずに起きた例外は、プログラムの強制終了を引き起こす。

try
{
    。。。
}

catch (型 変数)
{


}

例)
catch (Exception e) { 。。。

※全ての例外をキャッチするのであれば
│ catch (Exception ex) { 。。。

※特定の例外をキャッチするのであれば
例)
│ catch (System.IO.FileNotFoundException ex) {。。。

※特定の例外を複数キャッチするのであれば例外毎にcatchブロックを重ねる。

※例外の最後にExceptionクラスで全ての例外をキャッチできるブロックを置くのがよい。

※全ての例外クラスはExceptionクラスの派生クラスなので、Exceptionクラスは全ての例外をキャッチできる。
_◇catchブロックでの処理
│ ①即座に処理をすませる
│ ②現在の例外を別の例外でラップして再スローする
│ ⇒呼び出し元に関係の無い例外が発生した場合には有効
│ ⇒ラップした例外によっては問題の追及を難しくする
│ ③そのまま再スローする
※特定の例外を処理するようコードを記述するとよい
│ ⇒他の汎用的なcatchブロックでその他を捕まえる
※基底クラスの例外を指定した場合、その派生クラスの例外もキャッチされる

_◇try-catch-finally
│ try-catchに、例外の発生にかかわらず、常に実行されるfinallyブロックを追加したもの。
│ finallyブロックはリソースの開放等(ファイルのクローズなど)に使うと良い。

try
{
    。。。
}

catch (型 変数)
{


}

finally
{

}

※finallyブロックの中のコードは必ず実行される
│ ⇒tryおよびcatchブロックで、return, break, continue, gotoされても実行される
※リソースの後処理を確実にできる。
│ 例外をそこで処理できない場合でも、例外がスタックをさかのぼる前に使用中のリソースを開放するなどできる
※細かい粒度では、catchを除いて、try-finallyを配置し、コールスタックをさかのぼった先でcatchしてもよい

_◇throw
│ 明示的例外の通知。通常、tryブロックかcatchブロック内におかれる。

例)
tryブロック内:

    throw new DivideByZeroException("Div 0.");

catch (Exception e) {
 。。。
    Console.WriteLine(" Message:{0}", e.Message);
 。。。

※例外の再スロー
│ catchブロック内で
│  throw;
│ ⇒コールスタックをさかのぼって例外が伝搬する
│ (コールスタックは保持される)
│  throw ex;
│ とするとコールスタックはリセットされる
│ ⇒再スロー前の情報が失われる

※例外のスローは負荷の高い処理なので、スローが必要になる状況をできるだけ回避するべき

_◇Exceptionオブジェクト
│ スローされるExceptionオブジェクトには情報が含まれる。
│ Messageプロパティ
│  例外についてのメッセージ
│ Sourceプロパティ
│  エラーの原因となったオブジェクトやアセンブリの名
│ StatckTraceプロパティ
│  スタックトレース情報

※既定のException
│ InvalidOperationException
│  プロパティ、インデクサ、メソッドが呼ばれたときに適切な状態でない
│  (初期化されていないなど)ときにスローする
│ ArgumentException
│  引数に不正な値が指定された場合。なるべく具体的な以下の派生クラスを投げるべき
│  ArgumentNullException
│  ArgumentOutOfRangeException
│  InvalidEnumArgumentException
│ FormatException
│  値の形式が不正である場合にスローする

_◇オーバーフローのチェック
│ C#のデフォルトではオーバーフローのチェックは行わない。
│ ⇒大きな値を小さい値しか受け入れられない型にキャストした場合、情報の欠落が起こる
│ ※整数型の算術演算および変換に対して、オーバフローチェックを明示的に有効にする
│ ⇒あるいは抑制する

①checkedステートメントによりオーバーフローのチェックを行い、例外としてスローできる

例)

checked {
    。。。
}

例)
int result = checked( (int) (lhs + rhs) );

※lhsとrhsはlong型を想定
│ ⇒オーバーフローがあればOverflowExceptionが投げられる

②uncheckedステートメントによりオーバーフローのチェックを行わせないこともできる。

※各型の MaxValue フィールドと、MinValueフィールドで明示的にテストしてもよい

例)short.MaxValue

※浮動小数点型から整数型にキャストすると小数部分は切り捨てられる。整数部分がオーバーフローし、uncheckedコンテキストだと、結果は不定


◆イベント
│ 特殊な形式のデリゲート。
│ イベントはイベントを発生するクラスの中でのみ呼び出すことができる。

※EventHandlerデリゲートの派生クラスを型とする
│ イベントの発生源であるオブジェクト
│ System.EventArgsから派生したイベントに関連するデータを含むクラス


◆排他制御

_◇System.Threading.Monitorクラス

①排他制御が必要となる部分入る前に、 同期オブジェクトに鍵をかける。
②鍵がかかっている間、他のスレッドは同じオブジェクトに鍵をかけることは出来ず、 鍵がはずされるまで待たされる。
③鍵をかけたスレッドはクリティカルセクションを終えた後にオブジェクトにかかっている鍵をはずす。

※ロックの取得(lock)、ロックの解放(unlock)と呼ぶ。

※C# では参照型の任意の変数を同期オブジェクトとして使用できる。通常、
│ インスタンス変数に対する排他制御を行う場合、this を同期オブジェクトに使う
│ 静的変数に対しては typeof(クラス) を使う。

排他ロックをかけるためのクラスが System.Threading.Monitor クラス

※Enter メソッド
│ ロック取得

※Exit メソッド
│ ロック解放

_◇lock文


◆リソース管理

using文


◆マルチスレッド

マルチスレッドを使うための4つの方法がある。

_◇Threadクラス
System.Threading.Thread クラス

※スレッド作成手順
①スレッドで実行したい処理をメソッドとして記述
│ ⇒引数も戻り値もないメソッドとする
②作成メソッドに対してThreadStartデリゲートオブジェクトを作成する。
③上記のThreadStartデリゲートオブジェクトを Threadクラスのコンストラクタに渡す。
│ ⇒スレッドプールのように上限数の制限はない
②,③のステップの記述例)
Thread threadA = new Thread(
new ThreadStart(ThreadMethod));
⇒ThreadMethodが①で作成したメソッド
④ThreadクラスのStartメソッドを呼び出し、スレッドを開始。
記述例)
threadA.Start();
⑤ThreadクラスのJoinメソッドを呼び出し、スレッド終了を待つ。⇒必要ならば
⇒Joinメソッドは、スレッド終了まで現在のスレッドをBlock

スレッド作成例)

using System;
using System.Collections;
using System.Threading;

class Counter
{
  int id;

  public Counter(int id){this.id = id;}

  // スレッドの処理内容を記述する。
  // (この例では、ランダムな時間間隔で文字列を出力する。)
  public void Run()
  {
    Random rnd = new Random();

    for(int i=0; i<4; ++i)
    {
      Thread.Sleep(rnd.Next(50, 100));
│   // ランダムな間隔で処理を一時中断
      Console.Write("{0} (ID: {1})\n", i, id);
    }
  }
}

class TestThread
{
  static void Main()
  {
    const int N = 3;
    Thread[] threads = new Thread[N];
    // スレッド開始
    for(int i=0; i<N; ++i)
    {
      Counter counter = new Counter(i);
      // Thread クラス構築
      threads[i] = new Thread(new ThreadStart(counter.Run));

      // Start を使ってスレッドを開始
      threads[i].Start();
    }
    for(int i=0; i<N; ++i)
    {
      // Join を使ってスレッドの終了を待つ
      threads[i].Join();
    }
  }
}

_◇Threadにパラメータを渡す方法

※Threadクラスを使用したメソッドの呼び出しでは、直接パラメータを渡せない。

※スレッド処理を行うクラスを作成し、そのクラスのフィールドを通じて、スレッド処理するメソッドに何らかのデータを渡すことが多い

例)

public class ThreadClass
{
 private string text;
 。。。
 
 //スレッド起動用メソッド
 public void start(string s)
  {
    text = s; 
    Thread thread = new Thread(new ThreadStart(ThreadMethod));
    thread.Start();
  }

  //スレッド処理されるメソッド
  public void ThreadMethod()
  {
 。。。

_◇フォアグラウンド、バックグラウンド

Threadクラスにより実行したスレッドは、デフォルトで「フォアグラウンド・スレッド」となる
⇒そのスレッドが動作している限りアプリケーションは終了しない
※バックグラウンド・スレッド
メインのスレッドが終了すれば、バックグラウンド・スレッドは強制的に終了

※スレッドプールやデリゲートによるスレッドはバックグラウンド・スレッドとして実行される。

※スレッドの属性
Thread.IsBackgroundプロパティ
│ true バックグラウンド
│ false フォアグラウンド
デフォルトでフォアグラウンドのスレッドも属性変更することでバックグラウンドにできる

_◇TreadPoolクラス

※スレッドプール
プロセスに予め用意されているスレッドをプールして使いまわす仕組み
⇒スレッドプールはプロセスに1つ
⇒同時にアクティブにできるワーカスレッドは1システムプロセッサにつき25まで
⇒タイマやデリゲートなどもスレッドプールを使う
⇒一般に
│ Threadクラス:長期的に存在するスレッド
│ スレッドプール:短期的に生成・消滅するスレッド
と使い分けるのが良い

①別スレッドで実行したいメソッドを、「void メソッド名(object パラメータ)」の形式で作成

例)

private static void ThreadMethod(object state)
{
  ……
} 

②WaitCallbackデリゲートに、別スレッドで実行したいメソッド名を指定

WaitCallback waitCallback = new WaitCallback(ThreadMethod);

③ThreadPoolクラスのstaticメソッドである、QueueUserWorkItemメソッドにWaitCallbackデリゲートオブジェクトを指定

ThreadPool.QueueUserWorkItem(waitCallback, “A”);

※ThreadPool.QueueUserWorkItemメソッドの第2パラメータ=object型のパラメータ
│ 型チェックはなし
│ パラメータを渡すことができる

①~③によりスレッドプールにスレッドが登録され、後はスレッドプールが自動的に、キューに登録されたスレッドを順次実行する。

_◇非同期デリゲート
非同期デリゲートはメソッドを仮想化するだけでなく、メソッドの呼び出しを自動的にスレッドプールに代入して行う。これにより例外が捕捉でき、戻り値も取得できる。

※デリゲートオブジェクトのBeginInvokeメソッドで実行できる。

※実装はスレッドプールによっており、プロセス/プロセッサあたりのスレッド数に上限がある

①別スレッドとして処理したいメソッドと同じシグニチャのデリゲートを宣言
│ delegate DateTime ThreadMethodDelegate(string c);
│ ⇒パラメータの型と個数、戻り値の型は、別スレッドとして処理したいメソッドと同じ
│ ⇒BeginInvokeとEndInvokeはデリゲートに自動的に定義される
②デリゲートのインスタンスを作成し、インスタンスをフィールド変数(例えばthreadMethodDelegate)として保持
│ threadMethodDelegate = new ThreadMethodDelegate(ThreadMethod);
③コールバック・メソッドを作成
│ private static void MyCallback(IAsyncResult ar)
│ {
│  。。。
│ ⇒戻り値はvoid、パラメータをIAsyncResult型
│ ⇒コールバック・メソッドをBeginInvokeに知らせておく
│ ⇒非同期デリゲートの終了をブロックせずに知ることができる
│ ⇒コールバックメソッドの中でEndInvokeすればよい。

④デリゲートのBeginInvokeメソッドを呼び出しスレッドを開始
│ threadMethodDelegate.BeginInvoke(“.”, new AsyncCallback(MyCallback), DateTime.Now);
│ ⇒BeginInvokeはIAsyncResultオブジェクトを返す
│ ⇒IAsyncResultを引数にEndInvokeを呼び出す必要がある
│ ⇒コールバックメソッドを使えばコールバックメソッドの中で済ませられる。
│ ※コールバック・メソッドを利用しない場合、その引数を
│ ⇒nullとする
│ ※最後のパラメータ=ステート
│ ⇒object型のオブジェクト、内容任意
│ ⇒使用しない場合はnull

⑤戻り値の取得
│ ⇒デリゲート・オブジェクトに対してEndInvokeメソッドを呼び出す
│ ⇒EndInvokeメソッドは必ず呼び出す
│ DateTime result = threadMethodDelegate.EndInvoke(ar);
│ ※EndInvokeメソッドの戻り値は、デリゲートの戻り値と一致
│ ※EndInvokeメソッド
│ ⇒コールバック・メソッドのパラメータとして渡されるIAsyncResultオブジェクトを指定する
│ ※BeginInvokeメソッドの呼び出し時のステート
│ ⇒IAsyncResultオブジェクトのAsyncStateプロパティに格納されている

例)

using System;
using System.Threading;

public class List3
{
 // 戻り値とパラメータのあるデリゲート
 delegate DateTime ThreadMethodDelegate(string c);
 static ThreadMethodDelegate threadMethodDelegate;

 public static void Main()
 {
   threadMethodDelegate
    = new ThreadMethodDelegate(ThreadMethod); 
    // デリゲートによるスレッド処理呼び出し
   threadMethodDelegate.BeginInvoke(".",
     new AsyncCallback(MyCallback), DateTime.Now);
   Console.ReadLine();
 }

 // 別スレッドで呼び出されるメソッド
 private static DateTime ThreadMethod(string c)
 {
  // 10ミリ秒ごとに100回cを出力
  for (int i = 0; i < 100; i++)
  {
    Thread.Sleep(10);
    Console.Write(c);
  }
  return DateTime.Now;
 }

// スレッド処理終了後に呼び出されるコールバック・メソッド
 private static void MyCallback(IAsyncResult ar)
 {
  DateTime result = threadMethodDelegate.EndInvoke(ar);
  DateTime beginTime = (DateTime)ar.AsyncState; // 

  Console.WriteLine();
  Console.WriteLine(
   "{0}に処理を開始し、{1}に処理を完了しました。",
   beginTime, result);
 }
}

_◇非同期メソッド

非同期デリゲートと同様な仕組みで実行される非同期操作に非同期メソッドがある

_◇Timer
│ System.Threading名前空間のTimerクラス。ある一定時間毎に別スレッドの処理をしたい場合に用いる。

①TimerCallbackオブジェクトを作成して、一定期間ごとに実行するメソッドを登録
②Timerオブジェクトの作成時に、作成したTimerCallbackオブジェクトを指定する。
│ 3つめの引数 最初の実行まで待つ時間
│ 4つめの引数 実行する間隔
※ミリ秒単位で指定
③Dispose()メソッドでタイマースレッドを破棄

※実装はスレッドプールによっており、プロセス/プロセッサあたりのスレッド数に上限がある

_◇スレッドセーフとそうでないもの
│ スレッドセーフ(複数のスレッドから呼び出されても問題のない)クラスとそうでないものがある

※Consoleクラス
│ スレッドセーフ

※Windowsフォーム
│ スレッドセーフではない
│ ⇒コントロールを作成したスレッドからしか、メソッド、プロパティを呼び出してはいけない

※多くのインスタンスメンバはスレッドセーフではない
※スレッドセーフなメンバ呼び出しに対応するには同期が必須

_◇スレッドへの名づけ
│ スレッドに名前をつけておくことで制御に使える

※カレントスレッド
│ System.Threading.Thread.CurrentThread.Nameに名を与える

※インスタンス
インスタンス.Nameに名をあたえる

_◇マーシャリング(スレッド境界
│ スレッド境界を越えた実行
│ ⇒Windows Formなどはそのスレッドでないと操作できない
│ ⇒外部のスレッドはフォームの操作をそのフォームのスレッドに入って処理してもらう
│ Invoke
│  同期実行、呼び出し元はブロックされる
│ BeginInvoke
│  非同期実行、呼び出し元はブロックされない
│ EndInvoke

①コントロールのメソッドやプロパティを呼び出すためのメソッドを作成する
②メソッドに合ったデリゲートを宣言する
│ あるいは、既存の MethodInvoker.EventHandlerデリゲートを使う
│ ⇒ただしその場合は引数渡せず、戻り値もない
│ ?引数を渡せた。。。
③デリゲートオブジェクトを作成する
④コントロールやコントロールのあるフォームのInvokeメソッドにデリゲートオブジェクトを指定して呼び出す
※InvokeRequiredプロパティ
│ スレッドが異なるときにtrue
│ それ以外はfalseが返る

例)

delegate void xxx(); //別スレッドから呼び出す場合に使われるデリゲート

vod YYY()
{
    if (InvokeRequired) //別スレッドからの呼び出しを検出
    {
        Invoke(new xxx(YYY())); //別スレッドの場合、自分自身をInvoke
        return;
    }
    フォームなどの処理;
}

_◇排他制御

※競合状態 Race condtion

※クリティカルセッション
同時にひとつだけしかアクセスできないように制御する

_◇System.Threading.Monitor クラス
排他ロックをかけるために使うクラス

クリティカルセッションを保護するためのプリミティブなクラス
⇒使い方に注意が必要

①クリティカルセクションに入る前に、 あるオブジェクトに鍵をかける
⇒Enter

②鍵がかかっている間、他のスレッドは同じオブジェクトに鍵をかけることは出来ず、 鍵がはずされるまで待たされる。

③鍵をかけたスレッドはクリティカルセクションを終えた後にオブジェクトにかかっている鍵をはずす。
⇒Exit

※鍵をかける対象となるオブジェクトのことを同期オブジェクト、 鍵をかける操作のことを排他ロックと呼ぶ。
※鍵をかける操作をロックの取得(またはただ単にロック(lock))と呼び、 鍵をはずす操作をロックの解放(またはアンロック(unlock))と呼ぶ。

※静的メソッド
Enter メソッド
│ ロック取得
Exit メソッド
│ ロック解放
⇒一度 Monitor.Enter が呼ばれると、 Exit が呼ばれるまでの間、他のスレッドでは Enter より先に進めなくなる。

※Monitor クラスでは、参照型の任意の変数を同期オブジェクトとして使用できる
│ ⇒値型、文字列はロックに使わない
│ ⇒ロックがクラス内で完結するなら private 変数にする
│ ⇒インスタンスメソッド中で使うならメンバー変数
│ ⇒静的メソッド中で使うなら静的変数
│ private readonly object
│ syncObject = new object();
│ ⇒thisやTypeオブジェクトをLockに使用することが以前推奨
│ ⇒意図しなところで同じオブジェクトをlockに使われる危険あり
│ ⇒デッドロック発生の恐れ

※Exitを置く場所
│ System.Threading.Monitor.Enter(this);
│  。。。クリティカルセッション
│  。。。ここで例外が発生するとExitを通らずに抜けてしまう
│ System.Threading.Monitor.Exit(this);
│ ⇒処理の途中で例外が発生しても正しくロックを解放させる
│ ⇒Exit メソッドは finally ブロック内に記述

※排他制御の手順例)

object syncObject = new object();
Monitor.Enter(syncObject);
try
{
  クリティカルセクション
}
finally
{
  Monitor.Exit(syncObject);
}

_◇lock 文
排他制御のための専用の構文

lock(同期オブジェクト)
{
  クリティカルセクション
}

※lock 文を用いると、コンパイラが自動的に Monitor クラスを用いた排他制御用のコードを生成する

※volatile
│ 他のスレッドで値が更新されている可能性のある変数につける修飾子
│ ⇒volatile(ヴォラタイル: 揮発性、変わりやすい)
│ volatile 修飾子の付いた変数への値の読み書き
│ ⇒コンパイラの最適化によって削除されることはない。
※ただし、いくら一部でlockをかけても、lockを使用せずにクリティカルセッションに入るような別なコードがあれば排他制御できない。

_◇ManualResetEventクラス
待機ハンドル(WaitHandleオブジェクト)を使ってスレッド間で同期をとる

※待機ハンドル
│ シグナル状態
│  待機ハンドルをどのスレッドも所有していない
│ 非シグナル状態
│  待機ハンドルを所有されている

①まずどこかのスレッドでManualResetEventオブジェクトを生成
manualEvent = new System.Threading.ManualResetEvent(false);
⇒manualEvent変数はメソッドの外部で
public static ManualResetEvent
で宣言されているのでどのスレッドからも見える

②別スレッドを作成し、走らせる

③何か待ちたい側のスレッドで
manualEvent.WaitOne()
を実行すると、ここで実行がブロックされる

④待ちを外せる側のスレッドで
manualEvent.Set()
を実行すると、ブロックされていたスレッドが再開する

※但し、ManualResetEventオブジェクトは一度Setされると明示的にResetしない限りシグナル状態になってしまう
⇒必要あればWaitOne()から脱出後にResetする

※AutoResetEventクラス
シグナル待機中のスレッドを全て解放後、自動的に非シグナル状態に戻る

※複数の待機ハンドルを待つ
WaitAll 複数全てを待つ
WaitAny 複数のうちどれか1つを待つ

_◇TIPS

①デッドロック
│ クリティカルセッション内で他のlockを行うと発生しやすい
│ ⇒互いに待ちあってしまう
│ ⇒Monitor.TryEnterメソッドならタイムアウトで抜けること可能


◆メソッド

アクセス修飾子 型 メソッド名(パラメータリスト)
{
│ 。。。
}

※戻り値が無い場合voidを型として指定する。
※パラメータが複数ある場合にはカンマで区切る。
※パラメータが不要の場合はかっこだけにする

例)メソッドパラメータの例

enum Option { Date, Time, DateAndTime }

 。。。

static string GetNow(Option op)
{
 。。。

※戻り値が無い場合は、ブロック内の最後のステートメントが完了した後に呼び出し元に戻る。returnステートメントにより戻ることもできる。

_◇return
戻り値を指定し、呼び出し元に戻る。

_◇値渡しと参照渡し

値渡し
│ Passing by Value
│  値がコピーされてメソッドに渡されるので、メソッドでの操作は呼び出し元の変数に反映されない。
参照渡し
│ Passing by Reference
│  値型の場合、呼び出し元の変数に格納されている値への参照がコピーされて渡される
│  メソッドでの操作が呼び出し元の変数に反映される。
│  元の変数が参照型の場合には、変数が参照するオブジェクトへの参照が渡される
│  ⇒オプジェクトを操作することが可能。
│  ⇒ただし、呼び出し元の変数の参照の値自体は変えることはできない。

refキーワード
│ 変数を初期化してからパラメータとして渡す
outキーワード
│ 初期化不要だが、メソッドで代入することが必須

例) 参照渡し

int i = 100;
 。。。
GetDouble( ref i);
 。。。
static void GetDouble(ref int val)
{
    val *= 2;
 。。。

_◇イテレータ
│ メソッドから列挙子オブジェクト(列挙子インスタンス)を作成する。
│  IEnumerableインタフェース
│  yieldキーワード
│  yield return 値; 値を返す
│  yield break; 反復処理終了
│  を使う。

例)

public static IEnumerable GetNumber()
{
    for (int i = 1; i <= 5; i++)
    {
        yield return i;
    }
}

foreach (int i in GetNumber())
{
    。。。

_◇匿名メソッド
│ デリゲートとして利用できる式。
│ CLR機能でなく、C#コンパイラの機能。最終的にはデリゲートのインスタンスとなる

_◇ラムダ式
│ C# 3.0
│ クラスのメンバメソッドとは異なる文法で定義する匿名関数
│ ※1つの文でメソッドの定義や変数宣言を行うことができる
│ ※デリゲートとして呼び出すことができる

例)
j => j * 42

※C# 1.0での実装

public delegate int IncreaseByANumber(int j);

static public int MultipleByANumber(int j) {
  return j * 42;
}

public static void sample1()
{
  IncreaseByANumber increase =
    new IncreaseByANumber(MultipleByANumber);
  Console.Writeln(increase(10));
 。。。

※C# 3.0でのラムダ式による実装

public delegate int IncreaseByANumber(int j);

public static void sample3()
{
  IncreaseByANumber increase = j => j * 42;
  Console.Writeln(increase(10));
 。。。

※複数の引数を持つラムダ式の例
(j, k, l) => ((j * 42) / k) % l;

_◇拡張メソッド
│ extension method
│ クラスを継承することなく、
│ 静的クラスのなかに「拡張メソッド」の書式にしたがった静的メソッドを定義する
│ あたかも、あるクラスが拡張され、インスタンスメソッドが追加されたような形式
│ その静的メソッドを呼び出せるようになる。

※定義
│ 静的メソッドの第1引数の前にthisをつける

例)

static class StringExtensions
{
  public static string ToggleCase(this string s)

※呼び出し
│ 上記は通常の静的メソッドとしても呼び出せる
│ あたかもstring型のインスタンスメソッドであるかのようにも呼び出せる

string s1 = s.ToggleCase();

※拡張メソッドでは、クラス名を省略できる
│ ⇒同じ名前空間内に2つ以上同名の拡張メソッドを定義してはならない