Комментарии 22
Для одинаковых разделителей string.Join подойдет
+8
Join с уже готовой коллекцией работает. То есть сначала надо создать коллекцию, и только потом вызвать Join.
-4
В чем сложность? Дисклаймер, мне тот код который щас напишу не нравится =)
var l = new List<string>();
if (condition1) l.Add("CONDITION1 = ? ");
if (condition2) l.Add("CONDITION2 = ? ");
if (condition3) l.Add("CONDITION3 = ? ");
string sql = "SELECT * FROM table_1 WHERE " + string.Join(" AND ", l.ToArray());
0
Спасибо. Я люблю скоролить (с)
Есть же тег «source lang=cs» используйте его.
Есть же тег «source lang=cs» используйте его.
+3
1) Не уверен, так ли это в C#, но почти наверняка конкатенация — это лишний вызов конструктора (как в Java и JS).
2) Конкатенация в Append (см //первая порция и //последующие порции) сделана плохо. В результате каждый раз в цикле будет вычисляться этот дурацкий if (), который имеет смысл только для первого прохода.
Почему не бы сделать по такой схеме (псевдокод):
2) Конкатенация в Append (см //первая порция и //последующие порции) сделана плохо. В результате каждый раз в цикле будет вычисляться этот дурацкий if (), который имеет смысл только для первого прохода.
Почему не бы сделать по такой схеме (псевдокод):
content = elem[0];
while not end {
content += ', ' + elem[nextNdx]
}
+4
1) В C# аналогично. Нужно использовать StringBuilder для таких алгоритмов.
+8
1) Не уверен, так ли это в C#, но почти наверняка конкатенация — это лишний вызов конструктора (как в Java и JS).
Так и будет. Но это не то место, где можно получить большую экономию в скорости/памяти. Поэтому я и предпочел использовать более читаемый вариант.
2) Цикл в примере ниже написан только для краткости самого примера. Я имел ввиду ситуацию, когда каждое условие проверяется отдельно. Поэтому Append может и не вызваться ни разу. Или всего для 1,2 условий из, скажем, десятка.
Естественно, когда у нас сразу есть коллекция, подобные костыли не нужны и задача решается гораздо проще.
Так и будет. Но это не то место, где можно получить большую экономию в скорости/памяти. Поэтому я и предпочел использовать более читаемый вариант.
2) Цикл в примере ниже написан только для краткости самого примера. Я имел ввиду ситуацию, когда каждое условие проверяется отдельно. Поэтому Append может и не вызваться ни разу. Или всего для 1,2 условий из, скажем, десятка.
Естественно, когда у нас сразу есть коллекция, подобные костыли не нужны и задача решается гораздо проще.
-3
Мне кажется, вы путаете читаемость с примитивизмом.
+4
Вот тут я поспорю: что легче воспринимается?
или
И потом: простое != примитивное. Если уж на то пошло, вот такая строка (из комментария ниже) не примитивна, но и не читаема:
StringBuilder sb = new StringBuilder("1");
sb.Append("2");
string s = sb.ToString();
или
string s = "1" + "2";
И потом: простое != примитивное. Если уж на то пошло, вот такая строка (из комментария ниже) не примитивна, но и не читаема:
new [] { } .Where(p => p != null).Aggregate((f, s) => f + ', ' + s);
-3
Если через запятую:
new [] { } .Where(p => p != null).Aggregate((f, s) => f + ', ' + s);
Если нужно с последним «и», то будет чуть сложнее, но тоже не в 50 строчек.
new [] { } .Where(p => p != null).Aggregate((f, s) => f + ', ' + s);
Если нужно с последним «и», то будет чуть сложнее, но тоже не в 50 строчек.
0
Еще раз повторюсь:
последний пример был не очень удачным в том, что я сразу создал коллекцию как источник для фрагментов строк.
На самом деле речь идет о том, что у нас есть ряд независимых условий, каждое из которых проверяется отдельно. И только если это условие истинно, необходимо добавить в строку очередной фрагмент. А если работать с готовой коллекцией, то, разумеется, проще (как в первом комментарии):
s = string.Join(", ", arr);
последний пример был не очень удачным в том, что я сразу создал коллекцию как источник для фрагментов строк.
На самом деле речь идет о том, что у нас есть ряд независимых условий, каждое из которых проверяется отдельно. И только если это условие истинно, необходимо добавить в строку очередной фрагмент. А если работать с готовой коллекцией, то, разумеется, проще (как в первом комментарии):
s = string.Join(", ", arr);
-2
var filters = new[]{
new FuncTuple(() => true, "sdf"),
new FuncTuple(() => false, "sdfdfgdfg"),
new FuncTuple(() => true, "sddfgdfgf")
};
var s = string.Format("dfsdfsdfsd {0}", string.Join(", ", from x in filters where x.Item1() select x.Item2));
+1
Знание лямбда-функций и Linq НЕ означает, что их надо использовать везде, где только можно =)
-1
Конечно не означает. Но в данном случае, на моей взгляд, это уместней, чем вводить новые сущности, типа своего билдера. Кода у вас больше, работает он медленней из-за использования конкатенации и кастомной логики в нем больше, а значит больше вероятность ошибки. Опять же по хорошему на все ваши if'ы надо юниттесты писать. К тому же реализация вроде приведенного FilterList может использоваться, если понадобиться составлять список из числе или структур или модельных классов, каждому из которых соответствует определенный предикат.
+1
Интересно было бы сравнить по скорости/памяти ваш и мой подходы.
Хотя заметный выигрыш в такой постановке задачи сложно получить: смысл увеличивать скорость функции, которая вызывается раз в несколько минут (ну пусть, в несколько секунд)?
Хотя заметный выигрыш в такой постановке задачи сложно получить: смысл увеличивать скорость функции, которая вызывается раз в несколько минут (ну пусть, в несколько секунд)?
-1
Для любителей ООП
class FilterList<TResult>:IEnumerable<TResult>
{
private readonly List<Tuple<Func<bool>,TResult>> _filters = new List<Tuple<Func<bool>,TResult>>();
public void Add(Func<bool> predicate, TResult value)
{
_filters.Add(Tuple.Create(predicate, value));
}
public IEnumerator<TResult> GetEnumerator()
{
return (from x in _filters where x.Item1() select x.Item2).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
var t = new FilterList<string>
{
{()=>true, "fdgdgfg"},
{()=>false, "fdgsdfsdfdgfg"},
{()=>true, "fdgfhdhfdhgdgfg"},
};
var s = string.Join(", ", t);
-3
Если уж делать класс ListBuilder, то хотя бы сделать красиво.
1. Использовать StringBuilder
2. Флаг first — убрать нафиг, сделать просто проверку StringBuilder на null и создавать при добавлении первой непустой строки (так мы его не будем создавать без необходимости).
А еще проще и эффективнее — сделать расширение для StringBuilder'а. И сделать добавление как в первом варианте. Просто и эффективно.
1. Использовать StringBuilder
2. Флаг first — убрать нафиг, сделать просто проверку StringBuilder на null и создавать при добавлении первой непустой строки (так мы его не будем создавать без необходимости).
А еще проще и эффективнее — сделать расширение для StringBuilder'а. И сделать добавление как в первом варианте. Просто и эффективно.
+1
string BuildSQL(string arg1, string arg2, string arg3)
{
string sql = "SELECT * FROM table_1 WHERE 1=1 ";
if (arg1 != null) sql += "AND ARG1 = ? ";
if (arg2 != null) sql += "AND ARG1 = ? ";
if (arg3 != null) sql += "AND ARG1 = ? ";
return sql;
}
Ай-я-я-яай, кто же SQL собирает конкатенацией…
Во первых, это все можно реализовать с помощью, вами не любимого LINQ, хотя кроме CURSORов ORACLE, пожалуй. Но ведь то — совсем другой уровень…
И вот ведь вопрос, зачем здесь «WHERE 1=1», простите???
0
А разве этот топик не посвящен сложным типам конкатенаций, чтобы они формировали правильные запросы, к примеру, без лишних операций в нагрузку баз данных?
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Миникостыли: склеиваем строку из фрагментов