Одинарная кавычка является запуском и концом строки. Точка с запятой является концом оператора. Таким образом, если они делали выбор как это:
Select *
From Students
Where (Name = '<NameGetsInsertedHere>')
SQL стал бы:
Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
-- ^-------------------------------^
В некоторых системах, эти select
добрался бы, работал сначала сопровождаемый drop
оператор! Сообщение: не ВСТРАИВАЙТЕ ЗНАЧЕНИЯ В СВОЙ SQL. Вместо этого используйте параметры!
) Обратите внимание на эти:
Джомо Фишер - быстрое переключение с LINQ
Густаво Герра - StaticStringDictionary - быстрое переключение с LINQ еще раз
Вы можете использовать trie для хранения списка строк; попытки были разработаны для быстрого re trie val. Вот один из примеров реализации дерева в C #.
Обновление : Презентация PowerPoint по свернутым попыткам для Unicode и Ifo по реализации свернутого дерева для Unicode (не C #)
Рассматривали ли вы использование вместо этого класса HashSet (в .NET 3)?
Относительно вашей проблемы "когда список невелик"; если вы не против использования неуниверсальных коллекций, System.Collections.Specialized.HybridDictionary
сделает что-то вроде этого; он инкапсулирует System.Collections.Specialized.ListDictionary
, когда он маленький, или System.Collections.Hashtable
, когда он становится больше (> 10
). Стоит взглянуть?
В противном случае; возможно, вы могли бы использовать HashSet
с настраиваемым компаратором? Затем вы можете выбрать, насколько дорого GetHashCode ()
...
using System;
using System.Collections.Generic;
class CustomStringComparer : IEqualityComparer<string> {
public bool Equals(string x, string y) {
return string.Equals(x, y);
}
public int GetHashCode(string s) {
return string.IsNullOrEmpty(s) ? 0 :
s.Length + 273133 * (int)s[0];
}
private CustomStringComparer() { }
public static readonly CustomStringComparer Default
= new CustomStringComparer();
}
static class Program {
static void Main() {
HashSet<string> set = new HashSet<string>(
new string[] { "abc", "def", "ghi" }, CustomStringComparer.Default);
Console.WriteLine(set.Contains("abc"));
Console.WriteLine(set.Contains("abcde"));
}
}
Возможно, HybridDictionary здесь лучший вариант. Его внутреннее использование зависит от количества предметов в коллекции.
В итоге я сделал следующее:
private static bool Contains(List<string> list, string value)
{
bool contains = null != list.Find(str => str.ToLower().Equals(value.ToLower()));
return contains;
}
Я предполагаю, что вы могли бы создать метод расширения для List
, но этого было достаточно для моих нужд.
Кстати, если память не изменяет, при построении String ее HashValue предварительно вычисляется и сохраняется вместе со строкой в качестве оптимизации для этого типа варианта использования. Если вы используете символьный массив или StringBuilder, это явно не применимо, но для неизменяемой String это должно быть.
РЕДАКТИРОВАТЬ: Я ошибаюсь ... Java кеширует String HashCode, C # - нет.
Вы можете использовать интернирование строк сделать это очень быстро.
При построении списка вы должны сохранить интернированный формат требуемой строки (результат string.Intern ()
). Затем вам нужно сравнить интернированную строку с объектом .ReferenceEquals
- поскольку интернированные строки имеют ту же ссылку.
List<string> BuildList() {
List<string> result;
foreach (string str from StringSource())
result.Add(str.Intern());
return result;
}
bool CheckList(List<string> list, string stringToFind) { // list must be interned for this to work!
return list.Find(str => object.ReferenceEquals(str, stringToFind)) != null;
}
Это приведет к четырехбайтовому сравнению для каждого списка и одному проходу по исходная строка. Внутренний пул строк построен специально для быстрого сравнения строк и определения, существует ли она уже, поэтому внутренняя операция должна быть довольно быстрой.