Как обеспечить ошибку компиляции при изменении подписи при использовании ключевого слова "params"

У меня есть такой метод:

public void Foo(params string[] args) {
  bar(args[0]); 
  bar(args[1]);
}

Новые требования приводят к таким изменениям:

public void Foo(string baz, params string[] args) {
  if("do bar".Equals(baz)) {
    bar(args[0]); 
    bar(args[1]);
  }
}

Проблема в том, что, хотя я и изменил сигнатуру метода, ошибок компиляции не происходит, что, конечно, правильно, но я хочу, чтобы при каждом вызове были ошибки компиляции Foo метод, где аргумент baz не было указано. То есть, если вызов Foo до изменения было это:

Foo(p1,p2); //where p1 and p2 are strings

теперь он должен быть таким:

Foo(baz,p1,p2);

Если это не будет изменено таким образом, p1 будет назначен на bazи массив параметров args будет иметь длину 1 и OutOfBounds исключение будет брошено.

Каков наилучший способ изменить подпись и убедиться, что весь вызывающий код обновляется соответствующим образом? (Реальный сценарий где Foo живет в сборке, совместно используемой многими проектами, автоматически созданными на сервере сборки. Таким образом, ошибка компиляции будет простым способом обнаружить весь код, к которому нужно прикоснуться, чтобы учесть изменения.)

Изменить: Как отметил Даниэль Манн и другие, приведенный выше пример предполагает, что я не должен использовать params вообще. Поэтому я должен объяснить, что в моем примере с реальным миром аргументы args не всегда должны иметь два элемента, поскольку логика в Foo касается аргументов, которые могут содержать любое количество элементов. Итак, скажем, это Foo:

public void Foo(string baz, params string[] args) {
  if("do bar".Equals(baz)) {
    int x = GetANumberDynamically();
    for(int i = 0; i<x; i++)
      bar(args[i]); 
  }
}

2 ответа

Вот решение. Не меняйте прежнюю сигнатуру метода, просто добавьте Obsolete атрибут с указанием обоих аргументов.

[Obsolete("Use Foo(string, params string[]) version instead of this", true)]
public void Foo(params string[] args) {
  bar(args[0]); 
  bar(args[1]);
}

Затем создайте новый метод с новой подписью.

public void Foo(string baz, params string[] args) {
  if("do bar".Equals(baz)) {
    bar(args[0]); 
    bar(args[1]);
  }
}

Второй аргумент в Obsolete Атрибут обеспечивает ошибку компиляции. Без этого это просто вызывает предупреждение компиляции. Более подробная информация об атрибуте доступна на MSDN.

РЕДАКТИРОВАТЬ:

Основываясь на обсуждении в комментариях ниже, Даниэль Манн предложил интересную проблему.

Это не решило бы проблему. Что если вы называете Foo("a", "b")? В этом случае он по-прежнему будет вызывать устаревший метод только с двумя аргументами и вызывать ту же проблему.

Я бы посоветовал проверить, есть ли более одного аргумента, переданного через args перед звонком bar,

Самое простое решение - не использовать params Ключевое слово, если у вас есть необходимые параметры.

Очевидно, вы ожидаете args содержать как минимум два параметра. Можно с уверенностью сказать, что это необходимо. Почему бы не иметь такую ​​сигнатуру метода?

public void Foo(string baz, string requiredArgument1, string requiredArgument2, params string[] optionalArguments)

Это устраняет двусмысленность: это всегда потребует как минимум 3 аргумента.

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

Foo(baz: "bar", args: new [] {"a", "b", "c"});

Другие вопросы по тегам