Первичная стоимость с подстрокой - это удаление подстроки в новую строку. Используя Reflector вы можете увидеть это:
private unsafe string InternalSubString(int startIndex, int length, bool fAlwaysCopy)
{
if (((startIndex == 0) && (length == this.Length)) && !fAlwaysCopy)
{
return this;
}
string str = FastAllocateString(length);
fixed (char* chRef = &str.m_firstChar)
{
fixed (char* chRef2 = &this.m_firstChar)
{
wstrcpy(chRef, chRef2 + startIndex, length);
}
}
return str;
}
Теперь, чтобы попасть туда (обратите внимание, что это не Substring()
), он должен пройти 5 проверок длины и тому подобное.
Если вы ссылаетесь на одну и ту же подстроку несколько раз, то, возможно, стоит вытащить все один раз и сбросить гигантскую строку. Вы будете нести накладные расходы в массивах для хранения всех этих подстрок.
Если это, как правило, «одноразовый» доступ, то создайте его подстроку, в противном случае рассмотрите возможность разбиения вверх. Возможно, System.Data.DataTable
будет полезным? Если вы выполняете множественный доступ и анализируете другие типы данных, DataTable
выглядит для меня более привлекательным. Если вам нужна только одна запись в памяти за раз, тогда Dictionary<string,object>
должно быть достаточно для хранения одной записи (имена полей должны быть уникальными).
В качестве альтернативы, вы можете написать собственный универсальный класс, который будет обрабатывать чтение записей фиксированной длины. Укажите начальный индекс каждого поля и тип поля. Длина поля определяется по началу следующего поля (исключение - последнее поле, которое может быть выведено из общей длины записи). Типы могут быть автоматически преобразованы, например int.Parse()
, double.Parse()
, bool.Parse()
и т. Д.
RecordParser r = new RecordParser();
r.AddField("Name", 0, typeof(string));
r.AddField("Age", 48, typeof(int));
r.AddField("SystemId", 58, typeof(Guid));
r.RecordLength(80);
Dictionary<string, object> data = r.Parse(recordString);
Если рефлексия подходит вам по вкусу:
[RecordLength(80)]
public class MyRecord
{
[RecordFieldOffset(0)]
string Name;
[RecordFieldOffset(48)]
int Age;
[RecordFieldOffset(58)]
Guid Systemid;
}
Просто запустите свойства, где вы можете получить PropertyInfo.PropertyType
, чтобы узнать, как обращаться с подстрокой из записи; вы можете вытянуть смещения и общую длину из атрибутов; и вернуть экземпляр вашего класса с заполненными данными. По сути, вы можете использовать отражение, чтобы извлечь информацию для вызова RecordParser.AddField () и RecordLength () из моего предыдущего предложения.
Затем заверните все в аккуратный маленький класс без суеты:
RecordParser<MyRecord> r = new RecordParser<MyRecord>();
MyRecord data = r.Parse(recordString);
Может даже зайти так далеко, чтобы вызвать r.EnumerateFile("path\to\file")
и использовать синтаксис перечисления yield return
для анализа записей
RecordParser<MyRecord> r = new RecordParser<MyRecord>();
foreach (MyRecord data in r.EnumerateFile("foo.dat"))
{
// Do stuff with record
}