Я хотел бы спросить, есть ли более элегантный способ сделать это:
List<char> unallowed = new List<char>();
for (char c = '\u0000'; c <= '\u0008'; c++) {
unallowed.Add(c);
}
for (char c = '\u000B'; c <= '\u000C'; c++) {
unallowed.Add(c);
}
// And so on...
Мне нужно добавить в список несколько смежных диапазонов символов Юникода, и единственное, что я могу придумать для рефакторинга вышеприведенного кода, - это создать мой собственный метод, чтобы избежать повторного набора циклов for. И я даже не уверен, что это того стоит.
Хорошо, вы могли бы сделать что-то вроде:
List<char> chars = new List<char>();
chars.AddRange(Enumerable.Range(0x0000, 9).Select(i => (char)i));
chars.AddRange(Enumerable.Range(0x000B, 2).Select(i => (char)i));
Не уверен, что это того стоит, тем не менее - особенно с учетом необходимости использовать "счет", а не "конец". Вероятно, проще написать собственный метод расширения...
static void AddRange(this IList<char> list, char start, char end) {
for (char c = start; c <= end; c++) {
list.Add(c);
}
}
static void Main() {
List<char> chars = new List<char>();
chars.AddRange('\u0000', '\u0008');
chars.AddRange('\u000B', '\u000C');
}
Повторите свой комментарий; методы расширения не являются функцией .NET 3.5. Это функция С# 3.0. До тех пор, пока вы скомпилируете набор кодов для установки .NET 2.0/3.0 (в зависимости от ситуации), не имеет значения, не имеет ли клиент .NET 3.5; вам, однако, нужно определить ExtensionAttribute
- несколько строк кода:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute { }
}
Или просто пойдите для взлома и загрузите LINQBridge и используйте все LINQ-to-Objects в .NET 2.0.
Добавление метода добавления диапазона, вероятно, является самым простым рефакторингом, и я думаю, что это того стоит, просто потому, что он упрощает чтение диапазонов. Используя MiscUtil Range
класс, вы можете сделать что-то вроде:
list.AddRange('\u000b'.To('\u000c').Step(1))
но это было бы еще менее понятно, чем наличие дополнительного метода (возможно, метода расширения на List<char>
?) и записи:
list.AddCharRange('\u000b', '\u000c');
Дополнительный рывок в порядке для одного или двух вызовов, но если вы повторяете это несколько раз, вы действительно хотите избавиться от как можно большего количества постороннего текста, чтобы выделить полезные данные. Стыдно, что методы расширения не рассматриваются инициализаторами коллекции, так как в противном случае было бы очень аккуратное решение.
Вам определенно нужен List<char>
, хотя из-за других ограничений? Это похоже на то, что вы действительно хотите, чтобы Predicate<char>
говорил, разрешен ли символ, и который может быть реализован путем объединения диапазонов и т.д.
Было бы разумно иметь запрещенные символы Unicode в списке, который вы читаете из файла или внутреннего ресурса, а не жестко закодированы в приложении.
Вы можете поместить диапазоны в массив и выполнить цикл:
char[] ranges = {
'\u0000','\u0008',
'\u000b','\u000c',
'0','9',
'a','z'
};
for (int i = 0; i < ranges.Length; i++) {
for (char c = ranges[i++]; c <= ranges[i]; c++) {
unallowed.Add(c);
}
}
Это в значительной степени, как я создаю списки Char (на самом деле это произошло только вчера). Если у вас есть много диапазонов для добавления в список, вы можете сделать его немного проще/менее повторяющимся, указав такой метод, как AddUnallowed (char from, Char to), который добавляется в список.
В вашем коде есть несколько дубликатов, как вы уже узнали. И дублирование обычно плохое, и метод сделает ваш код более читабельным, поэтому он считает, что это того стоит. Как насчет метода расширения:
public static class YourHelper
{
public static void AddCharRange(this List<char> list, char first, char last)
{
for (char c = first; c <= last; c++)
{
list.Add(c);
}
}
}
а затем:
List<char> unallowed = new List<char>();
unallowed.AddCharRange('\u0000', '\u0008');
В зависимости от вашего варианта использования, я бы назвал метод "Unallow" вместо "AddCharRange".