ใช้คลาสวิธีการและพารามิเตอร์

เสร็จสมบูรณ์เมื่อ

วิธีการ คือ บล็อกรหัสที่ประกอบด้วยชุดของคําสั่ง โปรแกรมกําหนดให้คําสั่งปฏิบัติการโดยการเรียกเมธอด และระบุอาร์กิวเมนต์เมธอดที่จําเป็นใดๆ ใน C# ทุกคําสั่งที่ดําเนินการจะดําเนินการในบริบทของวิธีการ

ลายเซ็นวิธีการ

มีการประกาศวิธีการในคลาส ระเบียน หรือ struct โดยการระบุ:

  • ระดับการเข้าถึงที่เลือกได้ เช่น public หรือ private ค่าเริ่มต้นคือ private
  • ตัวแก้ไขที่เลือกได้ เช่น abstract หรือ sealed
  • ค่าที่ส่งกลับหรือ void ถ้าวิธีการ ไม่มี
  • ชื่อวิธีการ
  • พารามิเตอร์เมธอดใด ๆ พารามิเตอร์เมธอดอยู่ในวงเล็บและคั่นด้วยเครื่องหมายจุลภาค วงเล็บเปล่าระบุว่าเมธอด ไม่ต้องการพารามิเตอร์

ส่วนเหล่านี้ทํางานร่วมกันเพื่อสร้างลายเซ็นของเมธอด

สําคัญ

ชนิดผลลัพธ์ของวิธีการ ไม่ได้เป็นส่วนหนึ่งของลายเซ็นของวิธีการ เพื่อวัตถุประสงค์ในการโอเวอร์โหลดเมธอด อย่างไรก็ตาม เป็นส่วนหนึ่งของลายเซ็นของเมธอด เมื่อกําหนดความเข้ากันได้ระหว่างผู้รับมอบสิทธิ์และวิธีการที่ชี้ไป

ตัวอย่างต่อไปนี้จะกําหนดคลาสที่มีชื่อ 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 สองวิธี Drive มีชื่อเดียวกัน แต่มีชนิดพารามิเตอร์ที่แตกต่างกัน

การเรียกใช้วิธีการ

วิธีการ สามารถ อินสแตนซ์ หรือ แบบคงที่ คุณต้องสร้างอินสแตนซ์ของวัตถุเพื่อเรียกใช้เมธอดอินสแตนซ์บนอินสแตนซ์นั้น เมธอดอินสแตนซ์ทํางานบนอินสแตนซ์และข้อมูลของอินสแตนซ์นั้น คุณเรียกใช้เมธอดแบบคงที่โดยอ้างอิงชื่อของชนิดที่มีเมธอดอยู่ วิธีการแบบคงที่ไม่ทํางานกับข้อมูลอินสแตนซ์ การพยายามเรียกใช้เมธอดแบบคงที่ผ่านอินสแตนซ์ออบเจ็กต์สร้างข้อผิดพลาดของคอมไพเลอร์

การเรียกใช้เมธอด เหมือนกับการเข้าถึงเขตข้อมูล หลังจากชื่อออบเจ็กต์ (ถ้าคุณกําลังเรียกใช้เมธอดอินสแตนซ์) หรือชื่อชนิด (ถ้าคุณกําลังเรียกใช้เมธอดแบบคงที่) ให้เพิ่มรอบระยะเวลา ชื่อของเมธอด และเครื่องหมายวงเล็บ อาร์กิวเมนต์จะแสดงอยู่ภายในวงเล็บ และคั่นด้วยเครื่องหมายจุลภาค

ข้อกําหนดของเมธอดระบุชื่อและชนิดของพารามิเตอร์ใด ๆ ที่จําเป็น เมื่อผู้เรียกเรียกใช้วิธีการ จะมีค่าที่เป็นรูปธรรม ที่เรียกว่า อาร์กิวเมนต์ สําหรับแต่ละพารามิเตอร์ อาร์กิวเมนต์ต้องเข้ากันได้กับชนิดพารามิเตอร์ แต่ชื่ออาร์กิวเมนต์ ถ้ามีการใช้หนึ่งในรหัสการเรียกใช้ไม่จําเป็นต้องเหมือนกับพารามิเตอร์ที่ตั้งชื่อไว้ในเมธอด ในตัวอย่างต่อไปนี้ เมธอด Square ประกอบด้วยพารามิเตอร์ชนิดเดียว int ที่มีชื่อว่า i การเรียกใช้วิธีการแรกจะส่งผ่านเมธอด Square ตัวแปรของชนิด int ที่มีชื่อว่า numตัวแปรดังกล่าวจะส่งผ่านตัวแปรชนิด numประการที่สอง คือค่าคงที่ของตัวเลข ซึ่งค่าคงที่เหล่านี้รวมถึงค่าคงที่ของตัวเลขด้วย และนิพจน์ที่สาม


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 และส่งผ่านไปยังเมธอด ที่ชื่อ ModifyValue ที่เปลี่ยนแปลงค่าของตัวแปรเป็น 30 อย่างไรก็ตาม เมื่อเมธอด ส่งกลับค่าของตัวแปรจะไม่เปลี่ยนแปลง


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 กําหนด 44 ให้กับเขตข้อมูล value และส่งผ่านวัตถุไปยังเมธอด ModifyObject ตัวอย่างนี้โดยหลัก ๆ แล้วจะเหมือนกับตัวอย่างก่อนหน้า (ผ่านอาร์กิวเมนต์ตามค่าไปยังเมธอด) อย่างไรก็ตาม ผลลัพธ์จะแตกต่างกันเนื่องจากมีการใช้ชนิดการอ้างอิงแทนชนิดค่า การปรับเปลี่ยนที่ทําใน ModifyObject ไปยังเขตข้อมูล obj.value จะเปลี่ยนแปลงเขตข้อมูล value ของอาร์กิวเมนต์ rtด้วย เมื่อวิธีการ Main แสดงค่าของ 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 เกี่ยวข้องกับการสลับค่าของตัวแปร คุณส่งผ่านสองตัวแปรไปยังวิธีการโดยการอ้างอิง และวิธีการจะสลับเนื้อหา ตัวอย่างต่อไปนี้จะสลับค่าจํานวนเต็ม


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

การส่งผ่านพารามิเตอร์ reference-type ช่วยให้คุณสามารถเปลี่ยนค่าของการอ้างอิงเองแทนที่จะเป็นค่าของแต่ละองค์ประกอบหรือเขตข้อมูล

คอลเลกชันพารามิเตอร์

ในบางครั้ง ข้อกําหนดที่คุณระบุจํานวนอาร์กิวเมนต์ที่แน่นอนไปยังวิธีการของคุณเป็นแบบจํากัด โดยใช้คําสําคัญ params เพื่อระบุว่าพารามิเตอร์เป็นคอลเลกชันพารามิเตอร์ คุณอนุญาตให้เมธอดของคุณถูกเรียกใช้ด้วยจํานวนตัวแปรของอาร์กิวเมนต์ พารามิเตอร์ที่ติดแท็กด้วยคําสําคัญ params ต้องเป็นชนิดคอลเลกชัน และต้องเป็นพารามิเตอร์สุดท้ายในรายการพารามิเตอร์ของเมธอด

จากนั้นผู้เรียกสามารถเรียกใช้เมธอด ในสี่วิธีสําหรับพารามิเตอร์ params:

  • โดยการส่งผ่านคอลเลกชันของประเภทที่เหมาะสมที่มีจํานวนองค์ประกอบที่ต้องการ ตัวอย่างนี้ใช้นิพจน์ collection เพื่อให้คอมไพเลอร์สร้างประเภทคอลเลกชันที่เหมาะสม
  • โดยการส่งรายการคั่นด้วยจุลภาคของอาร์กิวเมนต์แต่ละรายการของประเภทที่เหมาะสมไปยังวิธีการ คอมไพเลอร์สร้างประเภทคอลเลกชันที่เหมาะสม
  • โดยการส่งผ่าน null
  • ด้วยการไม่ได้ให้อาร์กิวเมนต์กับคอลเลกชันพารามิเตอร์

ตัวอย่างต่อไปนี้กําหนดเมธอด ที่ชื่อ GetVowels ที่ส่งกลับโหวตทั้งหมดจากคอลเลกชันพารามิเตอร์ วิธี Main แสดงวิธีการเรียกวิธีการ สี่วิธี ผู้เรียกไม่จําเป็นต้องใส่อาร์กิวเมนต์ใด ๆ สําหรับพารามิเตอร์ที่มีตัวปรับเปลี่ยน 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 จะสามารถใช้ได้กับอาร์เรย์มิติเดียวเท่านั้น

ค่าผลลัพธ์ของวิธีการ

วิธีการสามารถส่งกลับค่าไปยังตัวเรียก หากชนิดผลลัพธ์ (ชนิด ที่แสดงอยู่ก่อนชื่อเมธอด) ไม่ voidวิธีการนี้สามารถแสดงค่าได้โดยใช้คําสําคัญ return คําสั่งที่มีคําสําคัญ return ตามด้วยตัวแปร ค่าคงที่ หรือนิพจน์ที่ตรงกับชนิดผลลัพธ์ จะส่งกลับค่านั้นไปยังตัวเรียกเมธอด จําเป็นต้องใช้วิธีการที่มีชนิดการแสดงผลลัพธ์แบบ nonvoid เพื่อใช้คําสําคัญ return เพื่อแสดงค่า คําสําคัญ return จะหยุดการดําเนินการของวิธีการ

ถ้าชนิดผลลัพธ์ voidคําสั่งส่งกลับที่ไม่มีค่าจะยังคงมีประโยชน์ในการหยุดการดําเนินการของวิธีการ หากไม่มีคําหลัก return วิธีการจะหยุดทํางานเมื่อถึงจุดสิ้นสุดของบล็อกโค้ด

ตัวอย่างเช่น สองวิธีนี้ใช้คําสําคัญ return เพื่อแสดงจํานวนเต็ม:


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

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

ตัวอย่างนี้ใช้สมาชิกแบบบังคับของนิพจน์เพื่อกําหนดค่าที่ส่งกลับของวิธีการ ไวยากรณ์นี้เป็นแบบย่อสําหรับวิธีการที่ใช้คําสั่งเดียว (นิพจน์) เพื่อคํานวณค่าที่ส่งกลับ

คุณยังสามารถเลือกที่จะกําหนดวิธีการของคุณด้วยเนื้อความของคําสั่งและคําสั่ง return ได้ดังนี้


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

หากต้องการใช้ค่าที่ส่งกลับจากเมธอด วิธีการเรียกใช้สามารถใช้การเรียกใช้เมธอด นั้นที่ใดก็ได้ที่ค่าชนิดเดียวกันอาจเพียงพอ คุณยังสามารถกําหนดค่าที่ส่งกลับให้กับตัวแปรได้อีกด้วย ตัวอย่างเช่น ตัวอย่างรหัสสามรายการต่อไปนี้บรรลุเป้าหมายเดียวกัน:


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);

บางครั้ง คุณต้องการให้วิธีการของคุณส่งกลับมากกว่าค่าเดียว คุณใช้ชนิดทูเพิล และสัญพจน์ทูเพิล เพื่อส่งคืนค่าหลายค่า ชนิดทูเพิลจะกําหนดชนิดข้อมูลขององค์ประกอบของทูเพิล สัญพจน์ทูเพิลให้ค่าจริงของทูเพิลที่ส่งกลับ ในตัวอย่างต่อไปนี้ (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 Accessor