Если вам нужно получить таблицу из строки с разделителями:
SET @str = 'function1;function2;function3;function4;aaa;bbbb;nnnnn';
SET @delimeter = ';';
SET @sql_statement = CONCAT('SELECT '''
,REPLACE(@str, @delimeter, ''' UNION ALL SELECT ''')
,'''');
SELECT @sql_statement;
SELECT 'function1' UNION ALL SELECT 'function2' UNION ALL SELECT 'function3' UNION ALL SELECT 'function4' UNION ALL SELECT 'aaa' UNION ALL SELECT 'bbbb' UNION ALL SELECT 'nnnnn'
Вы говорите, что смотрите на строки, как насчет чего-то подобного, о котором кто-то уже прокомментировал.
var items = new List<string>();
items.Add("string1");
items.Add("string2");
if (items.Contains("string2"))
{
// do something
}
Вы даже можете получить значения из какого-либо файла конфигурации, чтобы заполнить список.
Если вам действительно нужно проверить все эти условия, вы не можете избавиться от них. Вы можете только изменить его и сделать более читабельным, но логика остается той же.
Я очень удивлен, что никто ничего не упомянул о редизайне вашего кода. Вам действительно нужно 20 разных штатов? По моему опыту, многие состояния часто зависят от других состояний и, следовательно, часто логически избыточны для проверки.
Рефакторинг вашего кода может помочь вам лучше понять его и то, как состояния связаны друг с другом. Я бы начал здесь первым, если бы я был тобой :)
Хотя мне нравится решение Дарио (как я уже прокомментировал, я бы поместил его в булеву функцию, чтобы у меня не было нового в условии условия if ...) Я не уверен, что не так с:
if((something == -1) &&
(somethingElse == -1) &&
(elseElse == -1) &&
...
)
Я думаю, что это, вероятно, намного легче читать, чем много ((A & amp; B) || (C & amp; (D || E))), которые Мне приходится иметь дело с ...
И как-то так
Я объясню немного дальше. (И исправьте глупые ошибки: S)
//Interface to be able to which classes are able to give a boolean result used in the if stuff
public interface IResultable
{
bool Result();
}
//A list that is IResultable itself it gathers the results of the IResultables inside.
public class ComparatorList<T> : List<T>, IResultable where T : IResultable
{
public bool Result()
{
bool retval = true;
foreach (T t in this)
{
if (!t.Result())
{
retval = false;
}
}
return retval;
}
}
//Or two bools
public class OrComparator : IResultable
{
bool left;
bool right;
public OrComparator(bool left, bool right)
{
this.left = left;
this.right = right;
}
#region IResultable Members
public bool Result()
{
return (left || right);
}
#endregion
}
// And two bools
public class AndComparator : IResultable
{
bool left;
bool right;
public AndComparator(bool left, bool right)
{
this.left = left;
this.right = right;
}
#region IResultable Members
public bool Result()
{
return (left && right);
}
#endregion
}
// compare two ints
public class IntIsComparator : IResultable
{
int left;
int right;
public IntIsComparator(int left, int right)
{
this.left = left;
this.right = right;
}
#region IResultable Members
public bool Result()
{
return (left == right);
}
#endregion
}
Есть ли у вас много там, если заявления это может быть круто:)
Итак, у нас есть такая структура для проведения большого количества сравнений , Я приведу небольшой пример реализации.
//list of ands
ComparatorList<AndComparator> ands = new ComparatorList<AndComparator>();
ands.Add(new AndComparator(true,true));
//list of ors
ComparatorList<OrComparator> ors = new ComparatorList<OrComparator>();
ors.Add(new OrComparator(false, true));
//list of intiss
ComparatorList<IntIsComparator> ints = new ComparatorList<IntIsComparator>();
ints.Add(new IntIsComparator(1, 1));
//list of all things :)
ComparatorList<IResultable> collected = new ComparatorList<IResultable>();
collected.Add(ands);
collected.Add(ors);
collected.Add(ints);
// if all things are as they must be :)
if (collected.Result())
{
//Evertything is as it schould be :)
}
Это не так часто, чтобы увидеть так много предложений в одном «если». Обычно вы обнаруживаете, что вам нужно вложить «если», чтобы получить необходимую логику, когда вам нужно выполнить некоторую строку независимо от истинности некоторых условий. Я не говорю, вкладывайте их, если вам это не нужно, если все они должны быть проверены одновременно. Только если есть какая-то общая функциональность. Другим соображением является установка логической переменной с результатом некоторого набора этих условий, которые могут облегчить понимание. Если ваши переменные являются массивом или коллекцией, можете ли вы пройти через них? Вы тестируете их все против -1?
Выполните агрегатные операции со списком ваших значений.
if (new[] { something, somethingelse, ... }.All(x => x == -1)) {
}
* Редактировать: Предоставление данных дополнительной строки:
var Data = new[] { something, somethingelse, ... };
if (Data.All(x => x == -1)) {
}
Вы можете реорганизовать его как функцию и вернуть значение Enum, которое представляет истинный случай:
if(something != -1)
return MyEnum.Something;
if(somethingelse != -1)
return MyEnum.SomethingElse;
if(etc != -1)
return MyEnum.SomethingElseEntirely;
return MyEnum.None;
Еще один путь, который вы можете исследовать, - это использование составных выражений. Эти выражения (которые являются основой работы LINQ в .NET Framework) позволяют создавать деревья выражений на основе всех этих условий, а затем код бизнес-логики может просто работать с выражением верхнего уровня, чтобы получить результат «истина / ложь». .
Для оценки выражений вы можете использовать шаблон посетителей
Это позволяет легко составлять деревья условий. эти деревья могут быть сериализованы даже для того, чтобы вы могли сохранить условия, при которых вы приняли решение. Здесь есть много возможностей.
Предполагая, что все эти условия действительно необходимы, вы можете объединить условия в один или несколько Uber-Booleans или вызовов функций для улучшения читабельности.
Например,
bool TeamAIsGoForLaunch = BobSaysGo && BillSaysGo;
bool TeamBIsGoForLaunch = JillSaysGo && JackSaysGo;
if (TeamAIsGoForLaunch && TeamBIsGoForLaunch && TeamC.isGoForLaunch())
Разложите его в функцию и сделайте каждое условие охранной оговоркой:
int maybe_do_something(...) {
if(something != -1)
return 0;
if(somethingelse != -1)
return 0;
if(etc != -1)
return 0;
do_something();
return 1;
}
Похоже, у вас есть 3 фрагмента информации, которые вместе представляют определенное состояние в вашем приложении. Вместо того, чтобы включать эти 3 части состояния, почему бы не создать значение, которое инкапсулирует их? Затем вы можете использовать иерархию объектов или делегата во время создания, чтобы связать действие, которое вы пытаетесь выполнить.
Одна вещь, которую следует учитывать, - , почему у вас так много предложений. Подобно тому, как операторы SWITCH часто указывают на то, что вы должны перемещать варианты выбора в подклассы, большая сложная цепочка операторов IF может указывать на то, что вы объединяете слишком много концепций (и, следовательно, решений) в одном месте.
В качестве примера я буду использовать пример расчета комиссии. В одной из построенных мною комиссионных ставок зависит от суммы комиссионных, выплачиваемых оптовику, который передает часть розничному продавцу. Сумма, передаваемая от оптовика к розничному продавцу, зависит от конкретного соглашения между розничным продавцом и оптовым продавцом (на основании договора). Количество, которое оптовик получает, также зависит от продуктовой линейки, конкретного продукта и количества проданного продукта.
Помимо этого, существовали дополнительные правила «исключений», основанные на состоянии клиента, конкретных настройках продукта и т. Д. Все это можно разработать в сложной цепочке операторов IF, но вместо этого мы сделали управляемые данными приложения.
Поместив всю эту информацию в таблицы, мы смогли выполнить правила данных. Сначала срабатывают общие правила оптовика, а затем срабатывают любые правила переопределения. Затем, имея в своем распоряжении комиссию базового оптовика, мы заставим оптовика распространять общие правила розничного предприятия, а затем исключения из них.
Это превратило огромный шарик логики в простой четырехэтапный процесс, при котором каждый шаг просто выполнял запрос к базе данных, чтобы найти правильное правило для применения.
Это, конечно, может не применяться в вашей ситуации, но часто такой большой комплекс действительно означает, что либо недостаточно классов, разделяющих ответственность (еще одним решением нашей проблемы могли быть фабричные классы, которые содержали конкретные правила и переопределения), или функциональность должна управляться данными.
Я не знаю C #, но, похоже, он включает условный оператор . Если ваши условия короткие, вы можете заменить длинные цепочки if / elsif / else хорошими табличными структурами, например так:
return something == 0 ? 0
: somethingelse == -1 ? 1
: yetanotherthing > 2 ? 2
: 3; # default
Я делаю это так, как никто, кроме меня. Мне все равно, если код "выглядит хорошо". Если у меня есть> 1 тест в этом условном выражении, это означает, что я склонен хотеть еще большего, или я могу захотеть прокомментировать некоторые из них или нет, и я хочу упростить внесение таких изменений.
Итак, я кодирую это так:
if (true
&& test_1
&& test_2
...
)
{
...
}
Это позволяет легко закомментировать тесты или добавить новые в виде однострочных изменений.
Но я буду первым, чтобы признать, это не претендует на то, чтобы быть красивым.
Используйте ворота там, где это возможно.
оператор if
if(bailIfIEqualZero != 0 &&
!string.IsNullOrEmpty(shouldNeverBeEmpty) &&
betterNotBeNull != null &&
!betterNotBeNull.RunAwayIfTrue &&
//yadda
измененная версия
if(bailIfIEqualZero == 0)
return;
if(string.IsNullOrEmpty(shouldNeverBeEmpty))
return;
if(betterNotBeNull == null || betterNotBeNull.RunAwayIfTrue)
return;
//yadda
Есть много способов справиться с этим, но позвольте мне выбрать несколько.
Во-первых, есть случай, когда все критерии (все AND-критерии в вашем операторе if) + код, который нужно выполнить, если все они истинны, являются одноразовыми.
В этом случае используйте код, который у вас есть. Возможно, вы захотите сделать то, что несколько других уже предложили, переписать, чтобы использовать код типа Guard-clause.
Другими словами, вместо этого:
if (a && b && c && d && ......)
DoSomething();
... вы переписываете что-то похожее на это:
if (!a) return;
if (!b) return;
if (!c) return;
if (!d) return;
if (!...) return;
DoSomething();
Почему? Потому что, как только вы начинаете вводить OR-критерии в микс, становится трудно читать код и выяснять, что произойдет. В приведенном выше коде вы разделяете критерии для каждого оператора AND (& amp; & amp;), и, таким образом, код становится легче для чтения. По сути, вы переписываете код, говоря «если и то, и то, или другое, и третье, или что-то другое, то делаете что-то« чтобы быть », если это, затем выходите; если это другое; затем выходите; если какое-то Другое дело, затем выход; если ничего из вышеперечисленного, сделать что-то ".
Однако во многих случаях у вас также есть случай повторного использования. Если некоторые из этих критериев появятся где-то еще, но код, который будет фактически выполняться (DoSomething), не будет таким же, то я бы снова обратился к тому, что уже предложили другие. Перепишите критерии в методы, которые возвращают результат Boolean
в зависимости от результата оценки критериев.
Например, что легче читать, это?
if (a && b && c && d && e && f && (h || i) && (j || k) || l)
или это:
if (CanAccessStream() && CanWriteToStream())
при условии, что все эти буквы можно разделить на эти два критерия.
В этом случае я бы взял некоторые критерии и включил в эти методы и выбрал подходящее название для критериев.
Третий вариант, когда критерии отличаются в нескольких местах кода, но фактический код для выполнения остается тем же.
В этом случае я бы переписал так, чтобы вы сгруппировали критерии и наслоили методы так, чтобы вызов одного метода проверил некоторые критерии, а затем вызвал другой метод, который проверит некоторые другие критерии и т. Д.
Например, вы могли бы написать это:
if (stream != null && buffer != null && inBuffer > 0 && stream.CanWrite)
stream.Write(buffer, 0, inBuffer);
else
throw new InvalidOperationException();
или вы могли бы написать это:
if (inBuffer > 0)
{
Debug.Assert(buffer != null);
WriteToStream(buffer, inBuffer);
}
...
private void WriteToStream(Byte[] buffer, Int32 count)
{
if (stream.CanWrite)
stream.Write(buffer, 0, count);
else
throw new InvalidOperationException();
}
Я бы сказал, что второй способ легче читать, и он более многоразовый, чем первый.
Вы также можете разделить состояние на класс.
class mystate
{
int something;
int somethingelse;
int etc;
bool abletodostuff()
{
return (something == -1) && (somethingelse == -1) && (etc == -1);
}
}
Реорганизовать его в функцию.
bool Check()
{
return (something == -1) && (somethingelse == -1) && (etc == -1);
}
Кроме того, вы можете создать более читаемый код / логику в своей функции проверки.