Мне сложно описать эту проблему. Может быть, поэтому мне трудно найти хорошее решение (слова просто не работают). Позвольте мне объяснить с помощью кода:
// original code
enum Fruit
{
Apple,
Orange,
Banana,
}
...
Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
coreFruit();
else
pealFruit();
eatFruit();
Теперь представьте, что годы разработки проходят с этими тремя типами. Различные варианты вышеупомянутой логики распространяются на хранимые процедуры, пакеты SSIS, приложения для Windows, веб-приложения, приложения Java, сценарии Perl и т. Д.
Наконец:
// new code
enum Fruit
{
Apple,
Orange,
Banana,
Grape,
}
В большинстве случаев «система» работает нормально пока не будет использован виноград. Затем части системы действуют ненадлежащим образом, очищая и / или очищая виноград, когда это не нужно или нежелательно.
Каких правил вы придерживаетесь, чтобы избежать этих беспорядков? Я предпочитаю, чтобы старый код генерировал исключение, если он не был переработан для учета новых перечислений.
I ' Мы сделали снимок в темноте:
# 1 Избегайте "Not In Logic" вроде этого
// select fruit that needs to be cored
select Fruit from FruitBasket where FruitType not in(Orange, Banana)
# 2 При необходимости используйте тщательно сконструированные методы NotIn ()
internal static class EnumSafetyExtensions
{
/* By adding enums to these methods, you certify that 1.) ALL the logic inside this assembly is aware of the
* new enum value and 2.) ALL the new scenarios introduced with this new enum have been accounted for.
* Adding new enums to an IsNot() method without without carefully examining every reference will result in failure. */
public static bool IsNot(this SalesOrderType target, params SalesOrderType[] setb)
{
// SetA = known values - SetB
List<SalesOrderType> seta = new List<SalesOrderType>
{
SalesOrderType.Allowance,
SalesOrderType.NonAllowance,
SalesOrderType.CompanyOrder,
SalesOrderType.PersonalPurchase,
SalesOrderType.Allotment,
};
setb.ForEach(o => seta.Remove(o));
// if target is in SetA, target is not in SetB
if (seta.Contains(target))
return true;
// if target is in SetB, target is not not in SetB
if (setb.Contains(target))
return false;
// if the target is not in seta (the considered values minus the query values) and the target isn't in setb
// (the query values), then we've got a problem. We've encountered a value that this assembly does not support.
throw new InvalidOperationException("Unconsidered Value detected: SalesOrderType." + target.ToString());
}
}
Теперь я могу безопасно использовать такой код, как this:
bool needsCoring = fruit.IsNot(Fruit.Orange, Fruit.Banana);
Если этот код будет распространен по всей системе, исключения будут выброшены, когда Grape прибудет в город (qa поймает их всех).
Таков план в любом случае. Проблема кажется очень распространенной, но я не могу найти ничего в Google (вероятно, моя вина).
Как вы все справляетесь с этим?
ОБНОВЛЕНИЕ:
Я чувствую ответ Для решения этой проблемы необходимо создать механизм «ловить все остальное», который останавливает обработку и предупреждает тестировщиков и разработчиков о том, что новое перечисление требует рассмотрения. "switch ... default" отлично, если он у вас есть.
If C # didn ' t имеет переключатель ... по умолчанию, мы могли бы исправить приведенный выше код следующим образом:
Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
coreFruit();
else if(fruit == Fruit.Apple)
pealFruit();
else
throw new NotSupportedException("Unknown Fruit:" + fruit)
eatFruit();
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ:
Вам действительно не следует использовать какой-либо из приведенных выше псевдокодов. Он может (?) Компилироваться или даже работать, но на самом деле это ужасный код. Я видел много хороших решений в этой теме, если вы ищете подход, основанный на ООП. Хорошее решение, конечно, заключается в централизованном размещении всех переключений и проверок (меня поразил заводской метод). Помимо этого, также потребуется экспертная проверка кода.