Подтвердить что ты не робот

Принуждение именованных аргументов в С#

В С# 4 появилась функция под названием named arguments, которая особенно полезна в таких сценариях, как

int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)

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

p.s.

Для тех, кому это может понадобиться, и почему бы просто не использовать class/struct для использования инициализаторы объектов, есть сценарии, когда это невозможно, Подобно вызовам библиотек, которые не входят в ваш контроль или странные условные обозначения кода, вы должны подчиняться.

4b9b3361

Ответ 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.");

    }

Надеюсь, вам понравится:)