2013-12-05 3 views
8

У меня есть метод, как это:Как обеспечить ошибку компиляции на изменение подписи, в которой используется ключевое слово «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, а массив params args будет иметь длину 1 и исключение OutOfBounds.

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

Редактировать: Как указал Даниэль Манн и другие, приведенный выше пример предполагает, что я не должен использовать параметры вообще. Поэтому я должен объяснить, что в моем реальном мире не всегда так, что args должен иметь два элемента, поскольку касается логики в Foo, args может содержать любое количество элементов. Итак, допустим, это 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

Почему бы не изменить подпись, чтобы сделать что-то совершенно другое (хотел взять 'int' или что-то). Тогда во всех методах будет выбрана ошибка компиляции? Конечно, лучший способ - рефакторинг с помощью Resharper или аналогичный. –

+0

Чтобы добавить к @dav_i: если вы _first_ добавляете 'int' вместо' string', компилируете, изменяете весь код вызова, а затем меняете 'int' на' string'. Также обратите внимание, что 'if (« do bar ».Equals (baz)) {' - очень плохой пример, это звучит как другая перегрузка или требуется больше рефакторинга. – CodeCaster

+0

Сделайте то, что предлагает @OndrejJanacek. Это ___definitely___ лучший способ. –

ответ

3

Вот решение. Не меняйте прежнюю сигнатуру метода, просто добавьте атрибут 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.

EDIT:

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

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

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

+2

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

+0

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

+0

Да, но это не моя проблема. Это просто плохая конструкция, где OP предполагает, что через 'args' будут всегда два аргумента. –

2

Самое простое решение - не использовать ключевое слово params, если у вас есть .

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

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

Это устраняет неоднозначность: Это всегда требуют, по крайней мере, 3-х аргументов.

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

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

+0

Вы совершенно правы в моем примере с манекеном. К сожалению, в моем реальном мире не известно из контекста Foo, сколько строк требуется. (Аргументы используются для параметров для запросов, которые загружаются динамически.) –

+0

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

+0

@JunWeiLee. Он не обрабатывает разные контексты, просто динамический. Фактическое использование таково, что params string [] args становятся параметрами в запросе. Какой запрос/число параметров известно только во время выполнения. –

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

  • Нет связанных вопросов^_^