Именованные аргументы. Преимущества использования. Примеры использования именованных аргументов в методах, конструкторах, индексаторах, делегатах.

Именованные аргументы. Преимущества использования. Примеры использования именованных аргументов в методах, конструкторах, индексаторах, делегатах


Содержание


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

 


Связанные темы