Каковы правила для именованных аргументов и почему?
Рассмотрим такой метод
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:
И для названных аргументов это легкий ветерок.
Надеюсь, что это поможет:)