クラス メソッドとパラメーターを実装する

完了

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

メソッド シグネチャ

メソッドは、次を指定してクラス、レコード、または構造体で宣言されます。

  • publicprivateなど、オプションのアクセス レベル。 既定値は privateです。
  • abstractsealedなどの省略可能な修飾子。
  • 戻り値。メソッドに何も含まれていない場合は void
  • メソッド名。
  • 任意のメソッド パラメーター。 メソッド パラメーターはかっこで囲まれており、コンマで区切られます。 空のかっこは、メソッドにパラメーターが必要ないことを示します。

これらの部分は連携してメソッド シグネチャを形成します。

大事な

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

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


namespace MotorCycleExample
{
    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 つの Drive メソッドの名前は同じですが、パラメーターの型は異なります。

メソッドの呼び出し

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

メソッドの呼び出しは、フィールドへのアクセスに似ています。 オブジェクト名 (インスタンス メソッドを呼び出している場合) または型名 (静的メソッドを呼び出している場合) の後に、ピリオド、メソッドの名前、かっこを追加します。 引数はかっこ内に一覧表示され、コンマで区切られます。

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


public static class SquareExample
{
    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 evaluates 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;
    }
}

値と参照パラメーター

C# の型は、値型または参照型です。 既定では、値型と参照型の両方が値渡しでメソッドに渡されます。

値型パラメーター

値型が値によってメソッドに渡されると、オブジェクト自体ではなくオブジェクトのコピーがメソッドに渡されます。 したがって、呼び出されたメソッド内のオブジェクトに対する変更は、コントロールが呼び出し元に戻ったときに元のオブジェクトには影響しません。

次の例では、値型をメソッドに値渡しし、呼び出されたメソッドは値型の値の変更を試みます。 int型の変数 (値型) を定義し、その値を 20 に初期化し、変数の値を 30 に変更する ModifyValue という名前のメソッドに渡します。 ただし、メソッドから制御が戻った場合、変数の値は変更されません。


public static class ByValueExample
{
    public static void Main()
    {
        var 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 フィールドに加えられた変更により、引数の value フィールドも変更 rtMain メソッドが rt の値を表示すると、例からの出力が示すように、33 に更新されていることがわかります。


public class SampleRefType
{
    public int value;
}

public static class ByRefTypeExample
{
    public static void Main()
    {
        var rt = new SampleRefType { value = 44 };
        Console.WriteLine("In Main, rt.value = {0}", rt.value);
        ModifyObject(rt);
        Console.WriteLine("Back in Main, rt.value = {0}", rt.value);
    }

    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
        Console.WriteLine("In ModifyObject, obj.value = {0}", obj.value);
    }
}
// The example displays the following output:
//      In Main, rt.value = 44
//      In ModifyObject, obj.value = 33
//      Back in Main, rt.value = 33

参照型パラメーター

メソッド内の引数の値を変更し、コントロールが呼び出し元のメソッドに戻ったときにその変更を反映する場合は、パラメーターを参照渡しで渡します。 パラメーターを参照渡しで渡すには、ref キーワードまたは out キーワードを使用します。 また、値を参照渡ししてコピーを回避することもできますが、in キーワードを使用しても変更を防ぐことができます。

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


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

    private 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

ref パラメーターで使用される一般的なパターンには、変数の値のスワップが含まれます。 参照によって 2 つの変数をメソッドに渡すと、メソッドはその内容を入れ替えます。 次の例では、整数値をスワップします。


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

        Swap(ref i, ref j);

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

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

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

パラメーター コレクション

メソッドの引数の正確な数を指定する必要が制限されている場合があります。 パラメーターがパラメーター コレクションであることを示すために params キーワードを使用すると、可変数の引数を使用してメソッドを呼び出せるようにすることができます。 params キーワードでタグ付けされたパラメーターはコレクション型である必要があり、メソッドのパラメーター リストの最後のパラメーターである必要があります。

呼び出し元は、params パラメーターに対して次の 4 つの方法のいずれかでメソッドを呼び出すことができます。

  • 必要な数の要素を含む適切な型のコレクションを渡します。 この例ではコレクション式を使用するため、コンパイラは適切なコレクション型を作成します。
  • 適切な型の個々の引数のコンマ区切りリストをメソッドに渡します。 コンパイラは、適切なコレクション型を作成します。
  • null渡すことによって.
  • パラメーター コレクションに引数を指定しないこと。

次の例では、パラメーター コレクションからすべての母音を返す GetVowels という名前のメソッドを定義します。 Main メソッドは、メソッドを呼び出す 4 つの方法をすべて示しています。 呼び出し元は、params 修飾子を含むパラメーターの引数を指定する必要はありません。 その場合、パラメーターは空のコレクションです。


static class ParamsExample
{
    static void Main()
    {
        string fromArray = GetVowels(["apple", "banana", "pear"]);
        Console.WriteLine($"Vowels from collection expression: '{fromArray}'");

        string fromMultipleArguments = GetVowels("apple", "banana", "pear");
        Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");

        string fromNull = GetVowels(null);
        Console.WriteLine($"Vowels from null: '{fromNull}'");

        string fromNoValue = GetVowels();
        Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
    }

    static string GetVowels(params IEnumerable<string>? input)
    {
        if (input == null || !input.Any())
        {
            return string.Empty;
        }

        char[] vowels = ['A', 'E', 'I', 'O', 'U'];
        return string.Concat(
            input.SelectMany(
                word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
    }
}

// The example displays the following output:
//     Vowels from array: 'aeaaaea'
//     Vowels from multiple arguments: 'aeaaaea'
//     Vowels from null: ''
//     Vowels from no value: ''

手記

C# 13 より前では、params 修飾子は 1 次元配列でのみ使用できます。

メソッドの戻り値

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

戻り値の型が void場合でも、値のない return ステートメントは、メソッドの実行を停止するのに役立ちます。 return キーワードがないと、メソッドはコード ブロックの末尾に達すると実行を停止します。

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


class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2) =>
        number1 + number2;

    public int SquareANumber(int number) =>
        number * number;
}

この例では、式形式のメンバーを使用して、メソッドの戻り値を割り当てます。 この構文は、1 つのステートメント (式) を使用して戻り値を計算するメソッドの短縮形です。

ステートメント本体と return ステートメントを使用してメソッドを定義することもできます。


class SimpleMathExtnsion
{
    public int DivideTwoNumbers(int number1, int number2)
    {
        return number1 / number2;
    }
}

メソッドから返された値を使用するには、呼び出し元のメソッドは、同じ型の値で十分な任意の場所でメソッド呼び出し自体を使用できます。 戻り値を変数に割り当てることもできます。 たとえば、次の 3 つのコード例は同じ目標を達成します。


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 = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);

メソッドが 1 つ以上の値を返したい場合があります。 複数の値を返すには、タプル型タプル リテラル を使用します。 タプル型は、タプルの要素のデータ型を定義します。 タプル リテラルは、返されるタプルの実際の値を提供します。 次の例では、(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);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

呼び出し元は、次のコードを使用して、返されたタプルを使用できます。


var person = GetPersonalInfo("111111111");
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);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

GetPersonalInfo メソッドの前の呼び出しは、次のように変更できます。


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

メソッドが配列をパラメーターとして受け取り、個々の要素の値を変更する場合、メソッドが配列を返す必要はありません。 C# は値によってすべての参照型を渡し、配列参照の値は配列へのポインターです。

式形式のメンバー

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


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 アクセサー キーワードは使用しません。