2012-07-02 6 views
27

C# 4 введена функция, называемая named arguments, который особенно полезен в тех случаях, какПринуждение именованные аргументы в C#

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

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

p.s.

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

+4

я не вижу особого смысла в именованных аргументах, если ваши аргументы не являются дополнительными. –

+1

@BobKaufman Я бы догадался об обратном. Когда вы компилируете код, он «забывает», был ли он назван позиционным параметром, именем или значением по умолчанию. –

+1

Зачем вам это нужно? Является ли это конвенцией на вас? – driis

ответ

24

Нет, не на языке C#. Он всегда принимает позиционные параметры, если все параметры поставлены.

Вы можете build a custom FxCop rule или StyleCop rule, чтобы обеспечить соблюдение этого - как указано в комментариях, это, скорее всего, правило StyleCop, которое вас заинтересует (спасибо Kris).

+7

Вы не можете создать собственное правило FxCop, потому что правила FxCop работают с двоичными файлами, а не с источником, а именованные аргументы «скомпилированы». Я полагаю, вы могли бы создать обычное правило StyleCop. –

+0

@KrisVandermotten, я думаю, что вы правы, однако FxCop может извлечь информацию из PDB, но я не знаю, использует ли именованные параметры в PDB. Если это не так, я полагаю, что вместо этого требуется правило стиля. – driis

+2

Нет, что касается именованных параметров, это PDB: «компьютер говорит нет!». –

15

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

Вот решение:

int RegisterUser(
#if DEBUG 
     int _ = 0, 
#endif 
     string nameFirst = null, 
     string nameLast = null, 
     string nameMiddle = null, 
     string email = null) { /*...*/ } 

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

Действительно использование любая комбинация из названных параметров:

RegisterUser(); 
    RegisterUser(nameFirst: "Joe"); 
    RegisterUser(nameFirst: "Joe", nameLast: "Smith"); 
    RegisterUser(email: "[email protected]"); 

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

+2

С вашей директивой препроцессора компилятора он действует так, как будто 'int _ = 0' даже не существует, если символ DEBUG не определен, поэтому он не имеет никакого эффекта для сборки релиза ... Я не знаю, t думаю, что этот ответ делает то, что вы думаете, что он делает ... – Zack

+2

Эффект заключается в том, что неиспользуемый параметр «_» со значением по умолчанию заставляет остальные параметры использовать значения по умолчанию и называть их при вызове. – user4698855

+5

Уродливый, но умный. – joelsand

2

Я также искал способ форсировать именованные аргументы. Необязательные параметры могут быть опасными, особенно если у вас несколько параметров одного и того же типа. Перегрузки - это почти всегда более безопасное решение, но бывают случаи, когда у вас есть метод, который может принимать множество комбинаций аргументов, поэтому создание 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" }); 

Таким образом, у вас есть только один необязательный параметр er, и это для ваших необязательных параметров.

Редактировать: Возможно, я не читал OP правильно. Вы не используете дополнительные аргументы? Если нет, то этот ответ, вероятно, вам не поможет.

0

Я использую другой метод. В моей настройке у меня есть 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."); 

    } 

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

Смежные вопросы