次の方法で共有


メソッド (C# プログラミング ガイド)

メソッドは、一連のステートメントが含まれているコード ブロックです。 必要なメソッド引数を指定してプログラムからメソッドを呼び出すと、メソッド内のステートメントが実行されます。 C# では、実行されるすべての命令がメソッドのコンテキストで実行されます。

Main メソッドは、すべての C# アプリケーションのエントリ ポイントであり、プログラムの起動時に共通言語ランタイム (CLR) によって呼び出されます。 最上位レベルのステートメントを使用するアプリケーションでは、Main メソッドはコンパイラによって生成され、すべての最上位レベルのステートメントが含まれます。

この記事では、名前付きメソッドについて説明します。 匿名関数について詳しくは、「ラムダ式」をご覧ください。

メソッド シグネチャ

メソッドは、などのアクセス レベル、publicなどの省略可能な修飾子、戻り値、メソッドの名前、および任意のメソッド パラメーターを指定することで、privateabstract、またはsealedで宣言されます。 これらの部分が一緒にメソッドのシグネチャです。

Von Bedeutung

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

メソッド パラメーターはかっこで囲み、各パラメーターをコンマで区切ります。 かっこ内を空にすると、メソッドでパラメーターが不要なことを意味します。 このクラスには、次の 4 つのメソッドが含まれています。

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 must implement this.
    public abstract double GetTopSpeed();
}

メソッド アクセス

オブジェクトでメソッドを呼び出すことは、フィールドへのアクセスに似ています。 オブジェクト名の後にピリオド、メソッドの名前、かっこを追加します。 引数はかっこ内に一覧表示され、コンマで区切られます。 したがって、 Motorcycle クラスのメソッドは、次の例のように呼び出すことができます。

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 {speed}");
    }
}

メソッド パラメーターと引数

メソッド定義には、必要なパラメーターの名前と型を指定します。 コードを呼び出すと、メソッドは、各パラメーターの引数と呼ばれる具体的な値を提供します。 引数はパラメーター型と互換性がある必要がありますが、呼び出し元のコードで使用される引数名 (存在する場合) は、メソッドで定義されているパラメーターと同じである必要はありません。 例えば次が挙げられます。

public void Caller()
{
    int numA = 4;
    // Call with an int variable.
    int productA = Square(numA);

    int numB = 32;
    // Call with another int variable.
    int productB = Square(numB);

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

    // Call with an expression that evaluates to int.
    productC = Square(productA * 3);
}

int Square(int i)
{
    // Store input argument in a local variable.
    int input = i;
    return input * input;
}

参照渡しと値渡しの比較

既定では、 値型 のインスタンスがメソッドに渡されると、そのコピーはインスタンス自体ではなく渡されます。 したがって、引数に対する変更は、呼び出し元のメソッドの元のインスタンスには影響しません。 値型インスタンスを参照渡しするには、 ref キーワードを使用します。 詳細については、「 パラメーター Value-Type 渡す」を参照してください。

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

次の例に示すように、 class キーワードを使用して参照型を作成します。

public class SampleRefType
{
    public int value;
}

ここで、この型に基づくオブジェクトをメソッドに渡すと、オブジェクトへの参照が渡されます。 次の例では、 SampleRefType 型のオブジェクトをメソッド ModifyObjectに渡します。

public static void TestRefType()
{
    SampleRefType rt = new SampleRefType();
    rt.value = 44;
    ModifyObject(rt);
    Console.WriteLine(rt.value);
}

static void ModifyObject(SampleRefType obj)
{
    obj.value = 33;
}

この例は、引数を値渡ししてメソッドに渡すという点で、基本的に前の例と同じことを行います。 ただし、参照型が使用されるため、結果は異なります。 パラメーターModifyObjectvalueフィールドにobjが加えられる変更は、valueメソッドの引数rtTestRefTypeフィールドも変更します。 TestRefTypeメソッドは、出力として 33 を表示します。

参照型を参照渡しまたは値渡しで渡す方法の詳細については、「参照型パラメーターの引き渡し」と「参照型」を参照してください。

戻り値

メソッドは、呼び出し元に値を返すことができます。 戻り値の型 (メソッド名の前にリストされている型) が voidされていない場合、メソッドは return ステートメントを使用して値を返すことができます。 return キーワードに続いて戻り値の型に一致する値があるステートメントは、その値をメソッドの呼び出し元に返します。

値は、値または 参照によって呼び出し元に返すことができます。 ref キーワードがメソッド シグネチャで使用され、各return キーワードに従っている場合、値は参照によって呼び出し元に返されます。 たとえば、次のメソッド シグネチャと return ステートメントは、メソッドが呼び出し元への参照によって estDistance という名前の変数を返していることを示します。

public ref double GetEstimatedDistance()
{
    return ref estDistance;
}

また、 return キーワードは、メソッドの実行を中止します。 戻り値の型が voidの場合、値を持たない return ステートメントは、メソッドの実行を中止するときに役立ちます。 return キーワードがないと、メソッドはコード ブロックの末尾に達すると実行を停止します。 return キーワードを使用して値を返すには、void 以外の戻り値の型を持つメソッドが必要です。 たとえば、次の 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) を使用して値を格納することは省略可能です。 コードの読みやすさに役立つ場合や、メソッドのスコープ全体の引数の元の値を格納する必要がある場合に必要な場合があります。

メソッドから参照によって返される値を使用するには、その値を変更する場合は 、ref ローカル 変数を宣言する必要があります。 たとえば、 Planet.GetEstimatedDistance メソッドが参照によって Double 値を返す場合は、次のようなコードを使用して ref ローカル変数として定義できます。

ref double distance = ref Planet.GetEstimatedDistance();

呼び出し元の関数が配列をMに渡した場合、配列の内容を変更するメソッド (M) から多次元配列を返す必要はありません。 適切なスタイルまたは関数型の値のフローを得るために M から結果の配列を返す場合がありますが、C# はすべての参照型を値で渡し、配列参照の値が配列へのポインターであるため、必要ありません。 メソッド Mでは、配列の内容に対する変更は、次の例に示すように、配列への参照を持つ任意のコードによって監視できます。

static void Main(string[] args)
{
    int[,] matrix = new int[2, 2];
    FillMatrix(matrix);
    // matrix is now full of -1
}

public static void FillMatrix(int[,] matrix)
{
    for (int i = 0; i < matrix.GetLength(0); i++)
    {
        for (int j = 0; j < matrix.GetLength(1); j++)
        {
            matrix[i, j] = -1;
        }
    }
}

非同期メソッド

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

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

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

非同期メソッドには、通常、 Task<TResult>TaskIAsyncEnumerable<T>or voidの戻り値の型があります。 戻り値の型 void は主として、戻り値の型 void が必要なイベント ハンドラーの定義に使用されます。 void を返す非同期メソッドは待機できません。void を返すメソッドの呼び出し元は、このメソッドがスローする例外をキャッチできません。 非同期メソッドでは、タスクと同様の戻り値の型を持つことができます。

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

Main メソッドは、Taskの戻り値の型を持つ非同期メソッドの例です。 DoSomethingAsyncメソッドに進み、1 行で表されるため、asyncキーワードとawaitキーワードを省略できます。 DoSomethingAsyncは非同期メソッドであるため、次のステートメントに示すように、DoSomethingAsyncの呼び出しのタスクを待機する必要があります: await DoSomethingAsync();

class Program
{
    static Task Main() => DoSomethingAsync();

    static async Task DoSomethingAsync()
    {
        Task<int> delayTask = DelayAsync();
        int result = await delayTask;

        // The previous two statements may be combined into
        // the following statement.
        //int result = await DelayAsync();

        Console.WriteLine($"Result: {result}");
    }

    static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }
}
// Example output:
//   Result: 5

非同期メソッドは ref パラメーターまたは out パラメーターを宣言できませんが、そのようなパラメーターを持つメソッドを呼び出すことができます。

非同期メソッドの詳細については、「async および await を使用した非同期プログラミング」と非同期の戻り値の型に関するページを参照してください。

式本体の定義

一般的に、式の結果を使用してすぐに返すメソッド定義や、メソッドの本体として単一のステートメントを持つメソッド定義があります。 =>を使用してこのようなメソッドを定義するための構文ショートカットがあります。

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ステートメントに達すると、コード内の現在の場所が記憶されます。 反復子が次回呼び出されると、その場所から実行が再開されます。

foreach ステートメントを使用して、クライアント コードから反復子を呼び出します。

反復子の戻り値の型は、IEnumerableIEnumerable<T>IAsyncEnumerable<T>IEnumerator、または IEnumerator<T> にすることができます。

詳細については、「 反復子」を参照してください。

C# 言語仕様

詳細については、C# 言語仕様のを参照してください。 言語仕様は、C# の構文と使用法の決定的なソースです。

こちらも参照ください