Іменовані аргументи. Переваги використання. Приклади використання іменованих аргументів у методах, конструкторах, індексаторах, делегатах.

Іменовані аргументи. Переваги використання. Приклади використання іменованих аргументів у методах, конструкторах, індексаторах, делегатах


Зміст



1. Поняття іменованих аргументів (named arguments). Загальна форма

При передачі аргументів методу, порядок їх слідування співпадає з порядком слідування параметрів визначених в оголошенні методу. При передачі аргументу методу, його значення передається параметру, що має таку саму позицію в переліку параметрів при оголошенні методу.

Однак, мова C# дозволяє змінювати порядок передачі аргументів відповідним параметрам. У цьому випадку використовуються так звані іменовані аргументи. Іменований аргумент – це такий аргумент, який при виклику методу містить ім’я параметру, якому передається значення цього аргументу.

У випадку виклику методу з іменованим аргументом потрібно дотримуватись наступної загальної форми

parameter_name : value

де

  • parameter_name – ім’я параметру, якому передається значення value. У цьому випадку значення value є іменованованим аргументом;
  • value – іменований аргумент. Це може бути константа або змінна типу, що відповідає типу параметру.

Загальна форма виклику методу з одним іменованим аргументом має вигляд:

MethodName(parameter_name : argument_name);

де

  • MethodName – ім’я методу, що викликається з іменованим аргументом argument_name;
  • parameter_name – ім’я параметру методу, що отримує значення від argument_name;
  • argument_name – ім’я аргументу, що передається в parameter_name. Значення argument_name може бути і константою.

 

2. Приклади, що демонструють використання іменованих аргументів

Приклад 1. Задано метод Mult(), що отримує 2 цілочисельних значення і повертає їх добуток

// метод, що повертає результат добутку 2-х чисел
static int Mult(int a, int b)
{
  return a * b;
}

Нижче наведено код, що демонструє виклик методу з іменованими аргументами

// іменовані аргументи
int x = 3, y = 5, z = 7; // змінні в програмі
int res; // змінна - результат

res = Mult(a: x, b: y); // x=>a, y=>b, res = 3*5 = 15
res = Mult(a: 3, b: z); // 3=>a, z=>b, res = 3*7 = 21
res = Mult(b: 11, a: y); // 11=>b, y=a, res = 11*5 = 55

У вищенаведеному коді три рази викликається метод Mult().

Перший раз виклик Mult() наступний:

res = Mult(a: x, b: y);

При такому виклику:

  • значення змінної x передається параметру a методу Mult();
  • значення змінної y передається параметру b методу Mult().

Другий виклик Mult() має вигляд:

res = Mult(a: 3, b: z);

У цьому випадку:

  • значення константи 3 передається параметру a методу Mult();
  • значення змінної z передається параметру b методу Mult().

Третій виклик Mult() змінює позиції іменованих аргументів навпаки:

res = Mult(b: 11, a: y);

У цьому випадку:

  • позиції іменованих аргументів змінено: спочатку задається значення для параметру b, потім для параметру a. Такий виклик методу допускається згідно синтаксису C#;
  • внутрішній параметр b отримує значення аргументу-константи 11;
  • внутрішній параметр a отримує значення аргументу-змінної y.

Приклад 2. У даному прикладі метод Area() отримує 6 іменованих аргументів, які є координатами точок трикутника. Метод знаходить площу трикутника.

// метод обчислює площу трикутника заданого координатами точок
static double Area(double x1, double y1, double x2, double y2, double x3, double y3)
{
  double a, b, c;

  a = Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  b = Math.Sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3));
  c = Math.Sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));

  return a + b + c;
}

 При виклику методу іменовані аргументи слідують у довільному порядку

// обчислення площі трикутника
double area;
area = Area(x3: 3.0, y2: 4, x1: 2, y1: 4, y3: 7, x2: 0); // area = 9.40491834728767

 

3. Чи має значення порядок слідування іменованих аргументів при виклику методу?

Ні. Якщо в методі оголошуються тільки іменовані аргументи, то ці  аргументи можуть слідувати в довільному порядку при виклику методу.

 

4. Чи можна разом з іменованими аргументами у виклику методу використовувати позиційні (неіменовані) аргументи?

Можна, при умові, що виконується наступне правило:

  • визначення іменованих аргументів повинно слідувати після визначення позиційних (фіксованих) аргументів.

Наприклад. Задано метод Min(), що знаходить мінімум між трьома числами

// пошук мінімуму між 3 числами
static int Min(int a, int b, int c)
{
  int min = a;
  if (min > b) min = b;
  if (min > c) min = c;
  return min;
}

Виклик методу Min() буде коректний тільки тоді, коли іменовані аргументи слідують після фіксованих (звичайних) аргументів, як показано нижче

int x, y, z;
x = 5;
y = 8;
z = -3;

int min;

// помилка: після фіксованого аргументу z слідує іменований c:x
// min = Min(a: y, z, c: x);

// правильно: спочатку слідують фіксовані аргументи y,z потім іменований c:x
min = Min(y, z, c: x); // min = -3

// правильно: усі аргументи іменовані
min = Min(c: x, b: y, a: z); // min = -3

 

5. Чи може іменований аргумент приймати значення декілька разів при виклику методу?

Ні, не може. Іменований аргумент може використовуватись тільки один раз при виклику методу.

Наприклад. Для методу Min(), що знаходить мінімум між трьома цілочисельними параметрами

// пошук мінімуму між 3 числами
static int Min(int a, int b, int c)
{
  int min = a;
  if (min > b) min = b;
  if (min > c) min = c;
  return min;
}

виклик

// помилка: іменований аргумент a не може бути використаний декілька разів
min = Min(a: x, a: y, b: z);

видасть повідомлення про помилку:

Named argument 'a' cannot be specified multiple times

 

6. В яких елементах мови C# можуть використовуватись іменовані аргументи?

Іменовані аргументи можуть використовуватись у:

  • методах;
  • делегатах;
  • конструкторах класів;
  • індексаторах.

 

7. Які переваги дає використання іменованих аргументів?

Використання іменованих аргументів дає наступні взаємозв’язані переваги:

  • спрощуються виклики складних методів з багатьма параметрами при поєднанні фіксованих та іменованих аргументів;
  • підвищується наочність викликів методів, що потребують багатьох аргументів що мають складні імена;
  • іменовані аргументи є необхідні у випадках, де потрібна зайва багатослівність (інформативність) при виклику методів.

 

8. Приклад використання іменованих аргументів в конструкторах класів

Задано клас CPoint, що описує точку на координатній площині. Клас містить конструктор, що приймає два параметри

// клас, що описує точку на координатній площині
class CPoint
{
  double x, y;

  // конструктор класу
  public CPoint(double x, double y)
  {
    this.x = x;
    this.y = y;
  }

  // методи доступу
  // метод, що отримує необов'язкові аргументи за замовчуванням
  public void SetXY(double x = 0, double y = 0)
  {
    this.x = x;
    this.y = y;
  }

  // отримати значення x,y
  public void GetXY(out double x, out double y)
  {
    x = this.x;
    y = this.y;
  }
}

Тоді, використання конструкторів класу з іменованими аргументами може бути таким:

// виклик конструктора з іменованими аргументами
CPoint pt1 = new CPoint(y: 1, x: 2.5);

// виклик конструктора з фіксованими (позиційними) аргументами
CPoint pt2 = new CPoint(2, 3.8);

// виклик конструктора з одним фіксованим та одним іменованим аргументом
CPoint pt3 = new CPoint(2.2, y: 1.5);

// перевірка
double x, y;

pt1.GetXY(out x, out y); // x = 2.5, y = 1.0
pt2.GetXY(out x, out y); // x = 2.0, y = 3.8
pt3.GetXY(out x, out y); // x = 2.2, y = 1.5

// виклик методу, що отримує іменовані та необов'язкові аргументи одночасно
pt1.SetXY(y: 3.3); // x = 0, y = 3.3
pt1.GetXY(out x, out y);

У вищенаведеному прикладі три рази викликається конструктор CPoint для різних випадків.

 

9. Приклад використання іменованих аргументів у делегаті

Нехай задано оголошення типу делегату TInt, який:

  • отримує два цілочисельні параметри;
  • повертає цілочисельний параметр.
// оголосити тип делегату TInt
delegate int TInt(int a, int b);

Дано оголошення двох статичних методів, що оперують цілочисельними параметрами a, b.

// методи обробки цілих чисел
// добуток цілих чисел
static int Mult(int a, int b)
{
  return a * b;
}

// додавання цілих чисел
static int Add(int a, int b)
{
  return a + b;
}

Нижче демонструється використання іменованих аргументів у делегаті типу TInt для виклику методів.

// оголосити делегат типу TInt
TInt ti;
int res; // результат обчислення

// додати метод до делегату
ti = Mult;

// викликати делегат з іменованим параметром
res = ti(b: 4, a: 7); // res = 28

ti = Add;
res = ti(2, b: 11); // res = 13

 

10. Приклад використання іменованих аргументів в індексаторах

Задано клас Array, що реалізує масив цілих чисел. У класі оголошується:

  • два конструктори;
  • один індексатор.
// клас типу масив Array
class Array
{
  int[] A; // внутрішня змінна - масив

  // конструктори класу
  public Array()
  {
    A = null;
  }

  public Array(int size)
  {
    A = new int[size];
    for (int i = 0; i < A.Length; i++)
      A[i] = i;
  }

  // індексатори
  public int this[int index]
  {
    get
    {
      if ((A != null) && (A.Length > 0) && (index >= 0) && (index < A.Length))
        return A[index];
      return 0;
    }
    set
    {
      if (A == null)
        return;
      if (A.Length > 0)
        A[index] = value;
    }
  }
}

Нижче наведено програмний код, що демонструє використання індексатора класу Array, який отримує іменований аргумент

// створити екземпляр класу Array
Array A1 = new Array(10);

// використання індексатора з іменованим аргументом
int t;
t = A1[index: 3]; // t = A[3] = 3 - використання іменованого аргументу
t = A1[8]; // t = 8 - позиційний (фіксований) аргумент

A1[index: 5] = 13;
t = A1[5]; // t = 13

 

11. Чи можна у виклику методу поєднувати іменовані та необов’язкові (optional) аргументи?

Так, можна.

Наприклад. Задано метод Average3(), що знаходить середнє арифметичне між трьома величинами a, b, c які є вхідними параметрами. Усі три параметри a, b, c є необов’язковими аргументами. Вони отримують різні значення: a = 1, b = 2, c = 3.

// метод, що містить необов'язкові аргументи
static double Average3(int a = 1, int b = 2, int c = 3)
{
  return (a + b + c) / 3.0;
}

Можна різними способами викликати даний метод, поєднуючи іменовані та необов’язкові аргументи:

// поєднання необов'язкових аргументів з іменованими аргументами
double res;

// один аргумент іменований (b), два - необов'язкові (a, c)
res = Average3(b: 5); // res = Average3(1, 5, 3) = 3

// два аргументи іменовані (a,b), один - необов'язковий (c)
res = Average3(a: 8, b: 4); // res = Average3(8, 4, 3) = 5

// один аргумент іменований (c), два - необов'язкові (a,b)
res = Average3(c: 10); // res = Average3(1, 2, 10) = 4.3333333333

// два аргументи іменовані (a,c), один - необов'язковий (b)
res = Average3(c: 7, a: 1); // res = Average3(1, 2, 7) = 3.3333333333

 


Зв’язані теми