メソッド

メソッドは、一連のステートメントが含まれているコード ブロックです。 必要なメソッド引数を指定してプログラムからメソッドを呼び出すと、メソッド内のステートメントが実行されます。 C# では、実行されるすべての命令がメソッドのコンテキストで実行されます。 Main メソッドは、すべての C# アプリケーションのエントリ ポイントです。プログラムが開始されると、このメソッドが共通言語ランタイム (CLR) によって呼び出されます。

注意

このトピックでは、名前付きメソッドについて説明します。 匿名関数については、「匿名関数」を参照してください。

このトピックは、次のセクションで構成されています。

メソッド シグネチャ

メソッドは次の項目を指定することで class または struct で宣言されます。

  • publicprivate など、任意のアクセス レベル。 既定値は、private です。
  • abstractsealed など、任意の修飾子。
  • メソッドに何も与えられていない場合、戻り値または void
  • メソッド名。
  • メソッド パラメーター。 メソッド パラメーターはかっこで囲み、各パラメーターをコンマで区切ります。 かっこ内を空にすると、メソッドでパラメーターが不要なことを意味します。

これらのまとまりがメソッド シグネチャとなります。

注意

メソッドのオーバーロードを可能にするために、メソッドの戻り値の型はメソッドのシグネチャには含まれません。 ただし、デリゲートとそれが指すメソッドの互換性を決定する場合には、メソッドのシグネチャの一部となります。

次の例では、5 つのメソッドを含む Motorcycle という名前のクラスを定義します。

using System;

abstract class Motorcycle
{
   // Anyone can call this.
   public void StartEngine() {/* Method statements here */ }

   // Only derived classes can call this.
   protected void AddGas(int gallons) { /* Method statements here */ }

   // Derived classes can override the base class implementation.
   public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

   // Derived classes can override the base class implementation.
   public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

   // Derived classes must implement this.
   public abstract double GetTopSpeed(); 
}

Motorcycle クラスにオーバーロードされたクラス Drive が含まれていることに注意してください。 2 つのメソッドの名前が同じであり、パラメーターの種類で識別する必要があります。

メソッドの呼び出し

メソッドはインスタンスまたは静的になります。 インスタンス メソッドを呼び出すには、オブジェクトをインスタンス化し、そのオブジェクトでメソッドを呼び出す必要があります。インスタンス メソッドはこのインスタンスとそのデータを操作します。 メソッドが属する型の名前を参照して静的メソッドを呼び出します。静的メソッドはインスタンス データを操作しません。 オブジェクト インスタンス経由で静的メソッドを呼び出そうとすると、コンパイラ エラーが発生します。

メソッドを呼び出すことは、フィールドにアクセスするのと似ています。 オブジェクトの名前 (インスタンス メソッドを呼び出す場合) または型の名前 (static メソッドを呼び出す場合) の後ろに、期間、メソッドの名前、かっこを追加します。 引数はかっこの中に記述し、コンマで区切ります。

メソッド定義には、必要なパラメーターの名前と型を指定します。 呼び出し元からメソッドを呼び出すとき、各パラメーターに引数と呼ばれる具体的な値を指定します。 引数にはパラメーター型との互換性が必要ですが、呼び出し元のコードで引数名を使用する場合、引数名がメソッドで定義されるパラメーター名と同じである必要はありません。 次の例では、Square メソッドに型が inti という名前のパラメーターが 1 つ含まれています。 最初のメソッド呼び出しでは、型が intnum という名前の変数が Square メソッドに渡されます。2 つ目のメソッド呼び出しでは数値定数が、3 つ目のメソッド呼び出しでは式が渡されます。

public class Example
{
   public static void Main()
   {
      // Call with an int variable.
      int num = 4;
      int productA = Square(num);

      // Call with an integer literal.
      int productB = Square(12);

      // Call with an expression that evaulates to int.
      int productC = Square(productA * 3);
   }
   
   static int Square(int i)
   {
      // Store input argument in a local variable.
      int input = i;
      return input * input;
   }
}

メソッド呼び出しの最も一般的な形式では、位置引数が使用されます。これはメソッド パラメーターと同じ順序で引数を指定するものです。 そのため、Motorcycle クラスのメソッドは次の例のように呼び出されます。 たとえば、Drive メソッドの呼び出しには 2 つの引数が含まれます。この 2 つの引数は、メソッドの構文の 2 つのパラメーターに対応しています。 1 つ目は miles パラメーターの値になります。2 つ目は speed パラメーターの値になります。

class TestMotorcycle : Motorcycle
{
   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();

      moto.StartEngine();
      moto.AddGas(15);
      moto.Drive(5, 20);
      double speed = moto.GetTopSpeed();
      Console.WriteLine("My top speed is {0}", speed);            
   }
}

メソッドを呼び出すとき、位置引数の代わりに名前付き引数を使用することもできます。 名前付き引数を使用するとき、パラメーター名に続けてコロン (":") と引数を指定します。 必要なすべての引数が存在する限り、メソッドの引数の順序は問われません。 次の例では、名前付き引数を使用して TestMotorcycle.Drive メソッドを呼び出しています。 この例では、メソッドのパラメーター リストとは反対の順序で名前付き引数が渡されています。

using System;

class TestMotorcycle : Motorcycle
{
   public override int Drive(int miles, int speed)
   {
      return (int) Math.Round( ((double)miles) / speed, 0);
   }

   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();
      moto.StartEngine();
      moto.AddGas(15);
      var travelTime = moto.Drive(speed: 60, miles: 170);
      Console.WriteLine("Travel time: approx. {0} hours", travelTime);            
   }
}
// The example displays the following output:
//      Travel time: approx. 3 hours

位置引数と名前付き引数の両方を利用してメソッドを呼び出すことができます。 ただし、名前付き引数の後に位置指定引数を使用することはできません。 次の例では、前の例にあった TestMotorcycle.Drive メソッドを呼び出していますが、位置引数が 1 つ、名前付き引数が 1 つ使用されています。

var travelTime = moto.Drive(170, speed: 55);

継承されたメソッドとオーバーライドされたメソッド

型に明示的に定義されるメンバーに加え、型は、その基底クラスに定義されているメンバーを継承します。 マネージ型という系統のすべての型は @System.Object クラスから直接的または間接的に継承するため、すべての型が、@System.Object.Equals(System.Object)、@System.Object.GetType、@System.Object.ToString など、そのメンバーを継承します。 次の例では、Person クラスを定義し、2 つの Person オブジェクトをインスタンス化し、Person.Equals メソッドを呼び出して 2 つのオブジェクトが等しいかどうかを判断します。 ただし、Equals メソッドは Person クラスに定義されていません。@System.Object から継承されたものです。

using System;

public class Person
{
   public String FirstName;
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: False

型は継承されたメンバーをオーバーライドできます。override キーワードを使用し、オーバーライドされたメソッドを実装します。 メソッド シグネチャは、オーバーライドされたメソッドのそれと同じにする必要があります。 次の例は前の例と似ていますが、@Object.Equals(System.Object) メソッドをオーバーライドしている点が異なります。 (この 2 つのメソッドは一貫性のある結果を提供するため、@Object.GetHashCode メソッドもオーバーライドされます。)

using System;

public class Person
{
   public String FirstName;

   public override bool Equals(object obj)
   {
      var p2 = obj as Person; 
      if (p2 == null)
         return false;
      else
         return FirstName.Equals(p2.FirstName);
   }

   public override int GetHashCode()
   {
      return FirstName.GetHashCode();
   } 
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: True

パラメーターを渡す

C# の型は、値型参照型のどちらかに区別されます。 組み込みの値型の一覧については、「型と変数」を参照してください。 既定では、値型と参照型の両方が値によりメソッドに渡されます。

パラメーターを値で渡す

値型が値でメソッドに渡されるとき、オブジェクト自体の代わりにオブジェクトのコピーがメソッドに渡されます。 そのため、呼び出されたメソッドでオブジェクトに加えた変更は、コントロールが呼び出し元に戻ったとき、元のオブジェクトで反映されません。

次の例では、値型を値でメソッドに渡します。呼び出されたメソッドが値型の値を変更しようとします。 型 int (値型) の変数を定義し、その値を 20 に初期化し、ModifyValue という名前のメソッドに値を渡します。このメソッドは変数の値を 30 に変更します。 しかしながら、メソッドが戻ると、変数の値は元のままです。

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 20

参照型のオブジェクトが値でメソッドに渡されると、オブジェクトへの参照が値で渡されます。 つまり、メソッドは、オブジェクト自体ではなく、オブジェクトの場所を示す引数を受け取ります。 この参照を使用してオブジェクトのメンバーを変更した場合、コントロールが呼び出し元のメソッドに戻ると、オブジェクトで変更が反映されています。 ただし、メソッドに渡されるオブジェクトを置換しても、コントロールが呼び出し元に戻ったとき、元のオブジェクトで反映されません。

次の例では、SampleRefType という名前のクラス (参照型) を定義します。 SampleRefType オブジェクトをインスタンス化し、その value フィールドに 44 を割り当て、ModifyObject メソッドにオブジェクトを渡します。 この例は、基本的に前の例と同様に、引数を値でメソッドに渡しています。 ただし、参照型を使用しているため、結果は異なります。 ModifyObjectobj.value フィールドを変更したことで、Main メソッドの引数 rtvalue フィールドも 33 に変更されます。例の出力で確認できます。

using System;

public class SampleRefType
{
    public int value;
}

public class Example
{
    public static void Main()
    {
        var rt = new SampleRefType();
        rt.value = 44;
        ModifyObject(rt);
        Console.WriteLine(rt.value);
    }
        
    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
    }
}

パラメーターの参照渡し

メソッドの引数の値を変更し、コントロールが呼び出し元に戻ったときにその変更を反映させるには、参照でパラメーターを渡します。 パラメーターを参照で渡すには、キーワードの ref または out を使用します。

次の例は前の例とよく似ていますが、値が参照で ModifyValue メソッドに渡される点が異なります。 パラメーターの値が ModifyValue メソッドで変更されると、コントロールが呼び出し元に戻ったとき、地の変更が反映されます。

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(ref value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(ref int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 30

参照型パラメーターを利用する典型的なパターンが変数の値の入れ替えです。 参照でメソッドに 2 つの変数を渡すと、メソッドがその中身を入れ替えます。 次の例では、整数値が入れ替えられます。

using System;

public class Example
{
   static void Main()
   {
      int i = 2, j = 3;
      System.Console.WriteLine("i = {0}  j = {1}" , i, j);

      Swap(ref i, ref j);

      System.Console.WriteLine("i = {0}  j = {1}" , i, j);
   }

   static void Swap(ref int x, ref int y)
   {
      int temp = x;
      x = y;
      y = temp;
   }   
}
// The example displays the following output:
//      i = 2  j = 3
//      i = 3  j = 2

参照型パラメーターを渡すことで、個々の要素またはフィールドの値ではなく、参照自体の値を変更できます。

パラメーター配列

メソッドに厳密な数の引数を指定する要件が限定的になることがあります。 params キーワードを利用し、パラメーターがパラメーター配列であることを示すことで、可変数の引数でメソッドを呼び出すことができます。 params キーワードでタグが付けられたパラメーターは配列型にする必要があり、メソッドのパラメーター リストの最後のパラメーターにする必要があります。

呼び出し元は、次の 3 つの方法のいずれかでメソッドを呼び出すことができます。

  • 必要な数の要素を含む、適切な型の配列を渡す。
  • 適切な型の引数をコンマで区切った一覧をメソッドに渡す。
  • パラメーター配列に引数を指定しない。

次の例では、DoStringOperation という名前のメソッドを定義します。このメソッドは、その最初のパラメーターである StringOperation 列挙メンバーにより指定された文字列操作を実行します。 操作の実行対象である文字列はパラメーター配列により設定されます。 Main メソッドには、メソッド呼び出しの 3 つ全部の方法が入っています。 パラメーター配列に引数が指定されず、その値が null になるケースを処理するには、params キーワードでタグが付けられたメソッドを用意する必要があります。

using System;

class Example 
{
    static void Main() 
    {
        int[] arr = {1, 4, 5};
        Console.WriteLine("In Main, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);

        Change(ref arr);
        Console.WriteLine("Back in Main, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);
    }

    static void Change(ref int[] arr)
    {
        // Both of the following changes will affect the original variables:
        arr = new int[5] {-9, -7, -5, -3, -1};
        Console.WriteLine("In Change, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);
    }
}
// The example displays the following output:
//        In Main, array has 3 elements and starts with 1
//        In Change, array has 5 elements and starts with -9
//        Back in Main, array has 5 elements and starts with -9

省略可能なパラメーターと引数

メソッド定義では、そのパラメーターが必須であるか、任意であるかを指定できます。 既定では、パラメーターは必須です。 省略可能なパラメーターを指定するには、メソッド定義にパラメーターの既定値を追加します。 メソッドが呼び出されるとき、省略可能なパラメーターに引数が指定されていなければ、既定値が代わりに使用されます。

パラメーターの既定値は、次の種類の式のいずれかで割り当てる必要があります。

  • リテラル文字列や数値など、定数。
  • ValType が値型となる、new ValType 形式の式。 型の実際のメンバーではない、値型の暗黙の既定コンストラクターが呼び出されることに注意してください。
  • ValType が値型となる、default(ValType) 形式の式。

メソッドに必須のパラメーターと省略可能なパラメーターの両方が含まれる場合、省略可能なパラメーターはパラメーター リストの終わりに定義されます (すべての必須パラメーターの後に)。

次の例では、ExampleMethod メソッドを定義しています。必須のパラメーターが 1 つ、省略可能なパラメーターが 2 つあります。

using System;

public class Options
{
   public void ExampleMethod(int required, int optionalInt = default(int),
                             string description = "Optional Description")
   {
      Console.WriteLine("{0}: {1} + {2} = {3}", description, required, 
                        optionalInt, required + optionalInt);
   }
}

省略可能なパラメーターを複数持つメソッドが位置引数で呼び出された場合、呼び出し元は、引数が指定される最初のパラメーターから最後のパラメーターまで、すべての省略可能なパラメーターに引数を指定する必要があります。 たとえば、ExampleMethod メソッドの場合、呼び出し元が description パラメーターの引数を指定した場合、optionalInt パラメーターの引数も指定する必要があります。 opt.ExampleMethod(2, 2, "Addition of 2 and 2"); は有効なメソッド呼び出しです。opt.ExampleMethod(2, , "Addition of 2 and 0); は、"引数がありません" というコンパイラ エラーを発生させます。

メソッドが名前付き引数または位置引数と名前付き引数の組み合わせで呼び出される場合、呼び出し元は、メソッド呼び出しの最後の位置引数の後に続く引数を省略できます。

次の例では、ExampleMethod メソッドが 3 回呼び出されます。 最初の 2 つのメソッド呼び出しでは、位置引数が使用されます。 最初の呼び出しではいずれの省略可能なパラメーターも省略され、2 つ目の呼び出しでは最後の引数が省略されます。 3 つ目のメソッドは必須パラメーターの位置引数を指定しますが、名前付き引数を利用して description パラメーターに値を指定します。optionalInt パラメーターは省略します。

public class Example
{
   public static void Main()
   {
      var opt = new Options();
      opt.ExampleMethod(10);
      opt.ExampleMethod(10, 2);
      opt.ExampleMethod(12, description: "Addition with zero:");
   }
} 
// The example displays the following output:
//      Optional Description: 10 + 0 = 10
//      Optional Description: 10 + 2 = 12
//      Addition with zero:: 12 + 0 = 12

省略可能なパラメーターの使用は、オーバーロードの解決に影響を与えます。次のように、特定のオーバーロードをメソッド呼び出しで呼び出すかどうかを C# コンパイラが決定する方法に影響を与えます。

  • メソッド、インデクサー、コンストラクターのパラメーターのそれぞれが任意であるか、名前か位置により、呼び出しステートメントの 1 つの引数に対応するとき、その引数がパラメーターの型に変換できる場合、メソッド、インデクサー、コンストラクターが実行の候補になります。
  • 複数の候補が見つかった場合、明示的に指定される引数には、優先変換に関するオーバーロード解決の規則が適用されます。 任意のパラメーターの省略された引数は無視されます。
  • 2 つの候補が等しく良好であると判断された場合、呼び出しで引数が省略された任意のパラメーターのない候補が優先されます。 これはパラメーターの少ない候補に関するオーバーロード解決の一般優先設定の結果です。

戻り値

メソッドは、呼び出し元に値を返すことができます。 戻り値の型 (メソッド名の前に記述されている型) が voidでない場合、メソッドは、return キーワードを使用して値を返すことができます。 return キーワードに続いて変数、定数、または戻り値の型に一致する値が記述されたステートメントは、その値をメソッドの呼び出し元に返します。 戻り値の型が void 以外のメソッドで値を返すには、 return キーワードを使用する必要があります。 また、 return キーワードは、メソッドの実行を中止します。

戻り値の型が voidの場合、値を持たない return ステートメントは、メソッドの実行を中止するときに役立ちます。 return キーワードを使用しない場合、メソッドは、コード ブロックの最後に到達したときに実行を中止します。

たとえば、次の 2 つのメソッドは、 return キーワードを使用して整数を返します。

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2)
    {
        return number1 + number2;
    }

    public int SquareANumber(int number)
    {
        return number * number;
    }
}

メソッドから返された値を使用する場合、呼び出し元のメソッド内で同じ型の値を使用している場所では、メソッド呼び出し自体を値として使用できます。 戻り値は、変数に代入することもできます。 たとえば、次の 2 つのコードでは、同様の結果が得られます。

int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);

この場合、ローカル変数 resultを使用して値を格納する手順はオプションです。 このローカル変数によってコードの読みやすさが向上することがあります。また、引数の元の値をメソッドのスコープ全体で保持する場合に必要になることがあります。

メソッドで複数の値を返すと便利な場合があります。 C# 7.0 以降では、タプル型タプル リテラルを使用してこれを簡単に実行できます。 タプル型は、タプルの要素のデータ型を決定します。 タプル リテラルは、返されたタプルの実際の値を提供します。 次の例では、(string, string, string, int) は、GetPersonalInfo メソッドにより返されるタプル型を定義します。 式 (per.FirstName, per.MiddleName, per.LastName, per.Age) はタプル リテラルです。このメソッドは、PersonInfo オブジェクトの名、ミドルネーム、姓、年齢を返します。

public (string, string, string, int) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    if (per != null)
       return (per.FirstName, per.MiddleName, per.LastName, per.Age);
    else
       return null;
}

呼び出し元はそれから、次のようなコードで返されたタプルを利用します。

var person = GetPersonalInfo("111111111")
if (person != null)
   Console.WriteLine("{person.Item1} {person.Item3}: age = {person.Item4}");

名前は、タプル型の定義のタプル要素に割り当てることもできます。 次の例は、名前付き要素を使用する GetPersonalInfo メソッドの別バージョンです。

public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    if (per != null)
       return (per.FirstName, per.MiddleName, per.LastName, per.Age);
    else
       return null;
}

この例の GetPersonInfo メソッドの呼び出しは次のように変更できます。

var person = GetPersonalInfo("111111111");
if (person != null)
   Console.WriteLine("{person.FName} {person.LName}: age = {person.Age}");

メソッドに引数として配列が渡されるとき、そのメソッドが個々の要素の値を変更する場合、メソッドが配列を返す必要はありません。ただし、見やすいから、値の流れが機能的になるからといった理由で配列を返してもかまいません。 配列を返す必要がないのは、C# ではすべての参照型が値で渡され、配列参照の値がその配列のポインターになるためです。 次の例では、DoubleValues メソッドで行われた values 配列の内容の変更を、配列の参照があるあらゆるコードで観察できます。



using System;

public class Example
{
   static void Main(string[] args)  
   {  
      int[] values = { 2, 4, 6, 8 };
      DoubleValues(values);
      foreach (var value in values)
         Console.Write("{0}  ", value);
   }  
  
   public static void DoubleValues(int[] arr)
   {
      for (int ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
         arr[ctr] = arr[ctr] * 2;
   }
}
// The example displays the following output:
//       4  8  12  16

拡張メソッド

通常、既存の型にメソッドを追加する方法が 2 つあります。

  • その型のソース コードを変更する。 もちろん、型のソース コードを所有していない場合、これはできません。 また、メソッドをサポートするプライベース データ フィールドも追加した場合、これは互換性に影響する変更になります。
  • 派生クラスで新しいメソッドを定義する。 構造体や列挙型など、その他の型の継承を利用し、メソッドをこの方法で追加することはできません。 シール クラスにメソッドを "追加する" こともできません。

拡張メソッドでは、型自体を変更せずに、あるいは継承された型に新しいメソッドを実装せずに、既存の型にメソッドを "追加" できます。 また、拡張メソッドは、それが拡張する型と同じアセンブリに置く必要がありません。 型の定義済みメンバーのように拡張メソッドを呼び出します。

詳細については、「拡張メソッド」を参照してください。

非同期メソッド

非同期機能を使用することによって、明示的なコールバックを使用せずに、または複数のメソッドやラムダ式にわたって手動でコードを分割することなく、非同期メソッドを呼び出すことができます。

メソッドに async 修飾子を付けると、そのメソッドで await 演算子を使用できます。 コントロールが非同期メソッドの await 式に到達すると、待機中のタスクが完了していない場合、コントロールが呼び出し元に戻ります。await キーワードが与えられたメソッドの進行は、待機中のタスクが完了するまで中断されます。 タスクが完了すると、メソッドで実行を再開できます。

注意

非同期メソッドは、まだ完了していない待機中の最初のオブジェクトに達するか、または非同期メソッドの最後に達すると、呼び出し元に戻ります。

非同期メソッドの戻り値の型としては、@System.Threading.Tasks.Task、<TResult>、@System.Threading.Tasks.Task、`void` を指定できます。 戻り値の型 void は主として、戻り値の型 void が必要なイベント ハンドラーの定義に使用されます。 void を返す非同期メソッドは待機できません。void を返すメソッドの呼び出し元は、このメソッドがスローする例外をキャッチできません。 C# 7 がリリースされるとこの制約が緩和され、非同期メソッドでタスクと同種のあらゆる型を返すことができるようになります。

次の例では、DelayAsync は、整数を返す return ステートメントのある非同期メソッドです。 非同期メソッドであるため、そのメソッド宣言で戻り値の型 Task<int> を指定する必要があります。 戻り値の型が Task<int>であるため、次のステートメント int result = await delayTask に示すように、DoSomethingAsync 内の await 式を評価すると整数が生成されます。

using System;
using System.Diagnostics;
using System.Threading.Tasks;

public class Example
{
    // This Click event is marked with the async modifier.
    public static void Main()
    {
       DoSomethingAsync().Wait();
    }

    private static async Task DoSomethingAsync()
    {
        int result = await DelayAsync();
        Console.WriteLine("Result: " + result);
    }

    private static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }

    // Output:
    //  Result: 5
}
// The example displays the following output:
//        Result: 5

非同期メソッドで ref パラメーターまたは out パラメーターを宣言することはできませんが、これらのパラメーターが含まれたメソッドを呼び出すことはできます。

非同期メソッドの詳細については、「Async および Await を使用した非同期プログラミング」、「非同期プログラムにおける制御フロー」、「非同期の戻り値の型」を参照してください。

式形式のメンバー

メソッドの定義としては、式の結果を即座に返すか、またはメソッドの本文として 1 つのステートメントを含むものが一般的です。 =>を使用してこのようなメソッドを定義するための構文ショートカットがあります。


public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

メソッドが void を返すか、非同期メソッドである場合は、メソッドの本文を (ラムダの場合と同様に) ステートメント式にする必要があります。 プロパティとインデクサーは読み取り専用にする必要があるため、get アクセサー キーワードは使用しないでください。

反復子

反復子は、リストや配列など、コレクションに対するカスタム イテレーションを実行します。 反復子は、yield return ステートメントを使用して、各要素を 1 回に 1 つ返します。 yield return ステートメントに到達すると、現在の場所が記録されます。呼び出し元は、シーケンス内の次の要素を要求できます。

反復子の戻り値の型には、@System.Collections.IEnumerable、@System.Collections.Generic.IEnumerable%601、@System.Collections.IEnumerator、@System.Collections.Generic.IEnumerator%601 を指定できます。

詳細については、「反復子」をご覧ください。

関連項目

アクセス修飾子 静的クラスと静的クラス メンバー 継承 抽象クラス、シール クラス、クラス メンバー params out ref パラメーターを渡す