تنفيذ أساليب الفئة والمعلمات

مكتمل

الأسلوب هو كتلة تعليمات برمجية تحتوي على سلسلة من العبارات. يتسبب البرنامج في تنفيذ العبارات عن طريق استدعاء الأسلوب وتحديد أي وسيطات الأسلوب المطلوبة. في C#، يتم تنفيذ كل تعليمات منفذة في سياق أسلوب.

تواقيع الأسلوب

يتم تعريف الأساليب في فئة أو سجل أو بنية عن طريق تحديد:

  • مستوى وصول اختياري، مثل 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؛ الثاني، ثابت رقمي؛ والثالث، تعبير.


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

يتضمن النمط الشائع الذي يستخدم بواسطة معلمات المرجع تبديل قيم المتغيرات. تقوم بتمرير متغيرين إلى أسلوب حسب المرجع، ويتبادل الأسلوب محتوياتهما. يقوم المثال التالي بتبديل قيم عدد صحيح.


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:

  • بتمرير مجموعة من النوع المناسب الذي يحتوي على العدد المطلوب من العناصر. يستخدم المثال تعبير مجموعة بحيث يقوم المحول البرمجي بإنشاء نوع مجموعة مناسب.
  • بتمرير قائمة مفصولة بفواصل من الوسيطات الفردية من النوع المناسب إلى الأسلوب . ينشئ المحول البرمجي نوع المجموعة المناسب.
  • بتمرير 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 متبوعة بمتغير أو ثابت أو تعبير يتطابق مع نوع الإرجاع ترجع هذه القيمة إلى مستدعي الأسلوب. الأساليب ذات نوع الإرجاع غير المvoid مطلوبة لاستخدام الكلمة الأساسية 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 أو هو أسلوب غير متزامن، يجب أن يكون نص الأسلوب تعبير عبارة (مثل مع lambdas). بالنسبة للخصائص والمفهرسات، يجب أن تكون للقراءة فقط، ولا تستخدم الكلمة الأساسية get الملحق.