Именованные аргументы

— новое средство, которое появилось в С# 4.0. В действительности оно дополняет необязательные аргументы. Рассмотрим пример класса TeamMember, приведенный в предыдущем разделе. Предположим, что необходимо создать экземпляр TeamMember, приняв все аргументы конструктора по умолчанию за исключением isFullTime.

Для этого можно использовать именованные аргументы, как показано ниже:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
class TeamMember
{
public TeamMember ( string fullName,
string title = "Unknown",
string team = "Unknown",
bool isFullTime = false,
TeamMember   manager = null )  {
FullName = fullName;
Title = title;
Team = team;
IsFullTime = isFullTime;
Manager = manager;
}
public string FullName { get; private set; }
public string Title { get; private set; }
public string Team { get; private set; }
public bool IsFullTime{ get; private set; }
public TeamMember Manager { get; private set; }
}
static class EntryPoint {
static void Main()  {
TeamMember tm = new TeamMember ( "Peter Gibbons",
isFullTime : true ) ;
}
}

Обратите внимание на способ передачи аргумента isFullTime конструктору. Применять именованные аргументы легко. Необходимо просто указать имя аргумента, за которым следует двоеточие и значение, которое должно быть передано для этого аргумента. Остальные аргументы при вызове конструктора сохраняют свои значения по умолчанию. В приведенном выше вызове конструктора именованные аргументы фактически можно было бы использовать и для передачи значений обязательных аргументов.

При этом можно было бы изменить порядок аргументов в списке вызова:

1
2
3
4
5
static void Main()  {
TeamMember tm = new TeamMember(
isFullTime : true,
fullName : "Peter Gibbons" );
}

оказывают незначительное влияние на перегрузку методов. Позиционный список аргументов конструируется за счет комбинирования заданных позиционных аргументов вместе с именованными аргументами и всеми применимыми аргументами по умолчанию. Как только позиционный список аргументов сконструирован, разрешение перегрузок выполняется нормально. Единственное место, где именованные аргументы представляют сложность — это виртуальные переопределения.

Рассмотрим следующий надуманный пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
class А
{
public virtual void DoSomething ( int x, int у )  {
Console.WriteLine ( "{0},  {1}", x, у );
}
}
class В : A {
public override void DoSomething ( int y, int x )  {
base.DoSomething( у, x );
static class EntryPoint {
static void Main()  {
В b = new В () ;
b.DoSomething( x : 1, у : 2 );
A a = b;
a.DoSomething( x : 1, у : 2 ) ;
}
}

Это совершенно экстремальный пример, и поступать подобным образом в реальной разработке ни в коем случае нельзя! Запуск на выполнение приведенного выше кода дает следующий вывод:

2, 1
1, 2

При переопределении виртуального метода в типе-наследнике должно выполняться единственное требование — соответствие типов параметров и их позиций объявлению базового метода. Как было показано выше, действительные имена аргументов могут измениться. Проблема в том, что компилятор должен иметь надежную методику отображения именованного аргумента на позиционный аргумент виртуального метода. Он делает это, используя объявление метода статического типа переменной-ссылки.

В приведенном выше примере две ссылки а и b ссылаются на один и тот же экземпляр В. Однако при вызове DoSomething с именованными аргументами имеет значение объявление DoSomething, ассоциированное со статическим типом соответствующей ссылки. В первом вызове DoSomething через переменную Ь, поскольку ее статическим типом является В, именованные аргументы разрешаются на основе определения В.DoSomething.

Но в следующем вызове DoSomething через переменную а, из-за того, что ее статическим типом является А, именованные аргументы разрешаются через обращение к определению A.DoSomething. Как видите, этого следует избегать любой ценой, поскольку оно определенно вносит некоторую излишнюю путаницу в код.

И, наконец, следует учесть еще один момент: когда в списке аргументов присутствуют выражения, они вычисляются в том порядке, в котором появляются в списке, даже если этот список отличается от порядка позиционных параметров вызываемого метода.

Взгляните на следующий пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
class А
{
public void DoSomething ( int x, int у )  {
Console.WriteLine ( "{0},  {1}", x, у );
}
}
static class EntryPoint {
static void Main()  {
A a = new A () ;
a.DoSomething( GenerateValuel (), GenerateValue2 ()  );
// Теперь используем именованные аргументы
а.DoSomething ( у : GenerateValue2 (), х : GenerateValuel () );
}
static int GenerateValuel ()  {
Console.WriteLine ( "Вызов GenerateValuel" );
return 1;
static int GenerateValue2 ()  {
Console.WriteLine ( "Вызов GenerateValue2" );
return 2;
}
}

В результате запуска на выполнение приведенного выше кода получается следующий вывод:

1
2
3
4
Вызов GenerateValuel Вызов GenerateValue2
1, 2
Вызов GenerateValue2 Вызов GenerateValuel
1, 2

Обратите внимание, что порядок вызова методов GenerateValuel и GenerateValue2 зависит от порядка, в котором они появляются в списке аргументов, независимо от того, с какими позиционными параметрами они ассоциированы.

После того, как выражения вычислены — в данном случае, после вызовов GenerateValuel и GenerateValue2 — аргументы помещаются в их соответствующие позиции, чтобы найти лучший метод.

До появления именованных аргументов можно было писать код, в котором имел значение порядок вычисления выражений в списках параметров. Этот подход нельзя назвать удачным, как с именованными аргументами, так и без них. Предположим, что в предыдущем примере методы закодированы с побочным эффектом — исходя из того, что GenerateValuel будет всегда вызываться перед GenerateValue2.

Далее предположим, что метод A.DoSomething был вызван с использованием позиционных аргументов, когда текущей была версия С# 3.0.

Позднее, после появления именованных аргументов, инженер службы поддержки решил изменить код и передать аргументы в противоположном порядке, применив именованные аргументы — просто потому, что это дает более симпатично выглядящий код. Сразу же возникнет серьезная проблема!

Мораль этой истории в том, что следует избегать ситуации, когда приходится полагаться на определенный порядок вычисления выражений в списке аргументов.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100