Принуждение именованных аргументов в С#
В С# 4 появилась функция под названием named arguments, которая особенно полезна в таких сценариях, как
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
Есть ли способ принудительно использовать именованные аргументы? Может быть, какой-то атрибут применим к методу или к компилятору, о котором я не знаю? Я думаю, это можно сделать с помощью инструментов проверки кода, но просто хочу знать, есть ли другой способ.
p.s.
Для тех, кому это может понадобиться, и почему бы просто не использовать class/struct для использования инициализаторы объектов, есть сценарии, когда это невозможно, Подобно вызовам библиотек, которые не входят в ваш контроль или странные условные обозначения кода, вы должны подчиняться.
Ответы
Ответ 1
Нет, не на языке С#. Он всегда будет принимать позиционные параметры, если будут предоставлены все параметры.
Вы можете создать собственное правило FxCop или правило StyleCop для обеспечения соблюдения этого правила, как указано в комментарии, это, вероятно, правило StyleCop, которое вас интересует (спасибо Kris).
Ответ 2
Можно заставить вызывающих абонентов всегда использовать именованные аргументы. Я бы не делал этого в большинстве случаев, потому что это довольно уродливо, но это зависит от того, насколько требуется безопасное использование метода.
Вот решение:
int RegisterUser(
#if DEBUG
int _ = 0,
#endif
string nameFirst = null,
string nameLast = null,
string nameMiddle = null,
string email = null) { /*...*/ }
Первый параметр - это манекен, который не должен использоваться (и скомпилирован в Release для повышения эффективности). Тем не менее, он гарантирует, что все следующие параметры должны быть названы.
Допустимое использование - любая комбинация названных параметров:
RegisterUser();
RegisterUser(nameFirst: "Joe");
RegisterUser(nameFirst: "Joe", nameLast: "Smith");
RegisterUser(email: "[email protected]");
При попытке использовать позиционные параметры код не будет компилироваться.
Ответ 3
Я также искал способ форсировать именованные аргументы. Необязательные параметры могут быть опасными, особенно если у вас несколько параметров одного и того же типа. Перегрузки - это почти всегда более безопасное решение, но бывают случаи, когда у вас есть метод, который может принимать множество комбинаций аргументов, поэтому создание 20 перегрузок для учета любой возможности - это избыток.
В экстремальных ситуациях, когда крайне важно, чтобы аргументы были названы во все времена, я создам класс аргумента без определенного конструктора. В вашем случае вы можете сделать это:
public class UserRegistrationArguments
{
public string nameFirst { get; set; }
public string nameLast { get; set; }
public string nameMiddle { get; set; }
public string email { get; set; }
}
Назовите его следующим образом:
RegisterUser(new UserRegistrationArguments { nameFirst = "Bob", nameLast = "Slob" });
Вы также можете упростить его следующим образом:
public class UserRegistrationArguments
{
public string nameMiddle { get; set; }
public string email { get; set; }
}
int RegisterUser(string nameFirst, string nameLast, UserRegistrationArguments args = null)
... и выполните следующее:
RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" });
Таким образом, у вас есть только один необязательный параметр и для ваших необязательных параметров.
Изменить: Возможно, я не читал OP правильно. Вы не используете дополнительные аргументы? Если нет, то этот ответ, вероятно, вам не поможет.
Ответ 4
Я использую другой метод. В моей настройке у меня есть 1 параметр, который я всегда ожидаю, а затем придет куча необязательных строк, которые я действительно хочу быть уверенным, что пользователь выбрал активно. Таким образом, моя первая строка в этом списке является значением "trap", которое, если установлено, выдает ошибку. Вот так:
public HtmlString Toolbar(DynamicEntity target = null, string dontRelyOnParameterOrder = Constants.RandomProtectionParameter, string actions = null, string contentType = null, object prefill = null)
{
if (!Enabled) return null;
protectAgainstMissingParameterNames(dontRelyOnParameterOrder);
var toolbar = new ItemToolbar(target, actions, contentType, prefill);
return new HtmlString(toolbar.Toolbar);
}
private void protectAgainstMissingParameterNames(string criticalParameter)
{
if(criticalParameter != Constants.RandomProtectionParameter)
throw new Exception("when using the toolbar command, please use named parameters - otherwise you are relying on the parameter order staying the same.");
}
Надеюсь, вам понравится:)