Каковы правила для именованных аргументов и почему?

Рассмотрим такой метод

void RegisterUser(string firstname, string lastname, int age);

Мне нравится явно называть аргументы методов, подобных этому, когда я их вызываю, потому что для кого-то легко смешивать аргументы firstname и lastname. Однако это не обязательно для age. Например, я думаю, что это должно быть ОК с ясной точки зрения.

RegisterUser(firstname: "John", lastname: "Smith", 25);

Но будет выведена следующая ошибка:

Именованные аргументы должны появляться после того, как были определены все фиксированные аргументы

Еще одна интересная вещь: если подпись была

void RegisterUser(int age, string firstname, string lastname);

затем вызывая его следующим образом, НЕ выдает ошибку

RegisterUser(25, firstname: "John", lastname: "Smith");

Почему С# создан так? Есть ли осложнение для компилятора, если разрешен первый сценарий?

Ответы

Ответ 1

компилятор мог бы это понять, но для нас, простых людей, было бы почти невозможно узнать, относится ли 25 к 1-му или 3-му параметру. Тем более, что это открывает возможность смешивания аргументов. почему не

MyFunction(firstname: "josh", 25, "smith", someotherargument: 42)

Как бы вы это толковали, 25 для возраста и кузнеца для фамилии? создайте для него правило, и компилятор сможет его реализовать. Но что было бы разумно для людей. Обфускация кода не должна быть такой простой

Язык должен затруднять ошибки, а не проще

ПРИМЕЧАНИЕ: странные вещи начинают происходить с упорядочением, если более ранние аргументы называются позже. (например, первое имя и кузнец в моем примере), потому что тогда становится головоломкой для отображения ваших неназванных аргументов в правильные аргументы. это может быть сделано, но код не должен создавать головоломки

Ответ 2

Это связано с тем, что при указании аргументов компилятор сопоставляет его на основе имен и игнорирует определение функции, если присутствуют все необходимые аргументы. В вашем случае он не знает, что такое 25. Для нас это кажется логичным, что это должен быть возраст, но если вы измените свой пример на:

void RegisterUser(string firstname, string lastname, int age = 0, int weight = 0);

а затем скажите:

RegisterUser(firstname: "John", lastname: "Smith", 25);

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

Если вы не назовете свои аргументы, вы в основном говорите, что строго следуете структуре, установленной определением функции.

Ответ 3

Все именованные аргументы должны появляться после позиционных аргументов; вы не можете переключаться между стилями. Позиционные аргументы всегда ссылаются на соответствующий параметр в объявлении метода. Вы не можете сделать позиционные аргументы пропустить параметр, указав его позже с именованным аргументом. Компилятор использует временные локальные переменные. Затем он переупорядочивает этих локалей в слотах аргументов, я полагаю, что компилятор связывает аргументы по порядку, пока не найдет именованный аргумент, тогда он отбрасывает аргументы, которые он уже привязал без имен, и переупорядочивается, поскольку компилятор использует временные локальные переменные. Связывание остальных по имени, например, оно связывает 25 с возрастом, а затем переупорядочивает первое имя: "Джон", фамилия: "Смит"

Ответ 4

Предполагаемое использование:

void M(int a = -1, int b = -1, int c = -1, int d = -1, int e = -1);

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

M(42, 28, 101);  // gives a, b, and c in order; omits d and e

или вы можете использовать именованные аргументы:

M(d: 50, a: 42, c: 101);  // gives three arguments in arbitrary order

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

M(42, 28, e: 65537, d: 50);  // mixed notation OK

Причиной ограничения, с которым вы столкнулись, является то, что:

M(c: 101, 7, 9, b: 28, 666);  // ILLEGAL!

будет путать.

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

Я предлагаю вам назвать все аргументы, когда ваша причина использования именованного стиля является ясностью (в отличие от необходимости указывать только подходящее подмножество только параметров).

Ответ 5

Позиционные аргументы помещаются перед именованными аргументами. Позиционные аргументы всегда ссылаются на соответствующий параметр в объявлении метода.

Предположим, что мой метод:

void Dimensions(int height, int breadth , int length);

и я называю это как

Dimensions(3, length: 12, 24);

В этом случае:

'3' - первый параметр и относится к высоте, но '24' является третьим параметром и относится к длине, но мы уже указали значение длины.

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

Также, если мы определяем дополнительные параметры, предоставление позиционных параметров в конце может привести к неправильным результатам.

Ответ 6

Я думаю, что дизайн языка в этом случае управляет первым именованным аргументом любой функции.

Используя ваш пример

void RegisterUser(int age, string firstname, string lastname);

и называя его

RegisterUser(25, firstname: "John", lastname: "Smith");

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

25:

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

Firstname:

Как только он встретит первый аргумент, все изменится, так как компилятор теперь должен будет проверить все остальные аргументы, упомянутые в определении функции, для сопоставления текущего имени.

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

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

Lastname:

И для названных аргументов это легкий ветерок.

Надеюсь, что это поможет:)