РЕДАКТИРОВАТЬ: у меня теперь есть сообщение в блоге на эту тему , в котором более подробно.
По вашим номерам:
У меня может быть запись по 100 тыс. Для каждой записи, содержащей до 10 строк длиной от 30 до 60 символов.
Давайте начнем с добавления служебных данных объекта - строка занимает около 20 байт (IIRC - возможно, больше на 64-битном CLR) плюс фактических данных из-за неизбежных накладных расходов объекта и длина. Давайте снова посчитаем:
Использование строки: 1 миллион объектов при 20 + 120 байтах = 140 МБ
Использование нового класса: 1 миллион объектов размером 20 + 60 байт = 80 МБ
Разница, конечно, в 60 МБ, но пропорционально меньше, чем вы ожидали. Вы экономите только 42% пространства вместо 50%.
Теперь вы говорите о том, что дела идут быстрее: учитывая, что CLR изначально знает о string
, я подозреваю, что сторонний класс не сможет соответствовать скорости для некоторых своих операций, и вы нужно приложить много работы, чтобы многие другие работали с одинаковой скоростью. По общему признанию у вас будет улучшенная когерентность кэша, и если вы можете игнорировать проблемы с культурой, это также должно сэкономить немного времени, сделав все сравнения порядковыми.
Ради 60МБ я бы не стал беспокоиться. Это небольшая разница в наши дни - подумайте, сколько еще клиентов вы получите, сделав эту небольшую экономию, чтобы компенсировать значительную дополнительную стоимость работы с двумя различными типами строк.
Сказав все это, я все равно испытываю искушение реализовать его в качестве блогового проекта, такого как Edulinq. Не ожидайте результатов в течение нескольких недель или месяцев:)
РЕДАКТИРОВАТЬ: Я только что подумал о другой проблеме. Числа, которые мы получили выше, на самом деле не верны ... потому что класс строки особенный. Он встраивает свои данные непосредственно в объект - в отличие от любого другого типа данных, кроме массивов, размер экземпляра string
не является фиксированным; он варьируется в зависимости от данных в нем.
Написав свой собственный класс AsciiString
, вы не сможете этого сделать - вам нужно будет встроить ссылку на массив внутри класса:
public class AsciiString
{
private readonly byte[] data;
}
Это означает, что вам понадобятся дополнительные 4 или 8 байтов для ссылки (32 или 64-битный CLR) и дополнительные издержки объекта массива (16 байтов, IIRC) на строку.
Если вы спроектировали его как Java, взятие подстроки может повторно использовать существующий байтовый массив (две строки могут совместно использоваться), но тогда вам потребуется дополнительная длина и смещение в пределах AsciiString
. Вы также потеряете некоторые преимущества когерентности кэша.
Вы могли бы использовать только необработанные байтовые массивы в качестве структуры данных и написать множество методов расширения, чтобы воздействовать на них ... но это было бы ужасно, так как тогда вы не могли бы увидеть разницу между обычный байтовый массив и массив, который должен был представлять строку ASCII.
Другой возможностью было бы создать такую структуру:
struct AsciiString
{
private readonly byte[] data;
...
}
Это фактически даст вам сильный набор текста снова, но вам нужно подумать о таких вещах, как:
AsciiString x = new AsciiString();
, который в итоге будет иметь нулевую ссылку data
. Вы можете эффективно обработать это, как если бы x
было нулевым значением, но это было бы довольно не-идиоматично.