Результаты показались настолько интересными, что решил создать новую тему.
На всякий пожарный сделал проверку качества сериализации путем загрузки данных в другой DataSet и сравнения с исходным. Вариант Trantor-а не прошел проверку. Оказалось, что дата записанная в стринг по средствам ToString() и считанная обратно теряет точность. Так что вариант со строковой сериализацией нужно еще дописывать. Если вообще нужна строковая сериализация. Ведь разница в скорости почти 4 раза, и в размерах данных примерно в 1.7 раза.
За одно измерил время загрузки. Результаты оказались дико интересным! Гляньте на результаты BinaryFormatter-а! Загрузка почти в два раза медленнее чем у любого другого. А по сравнению сDetaSetCustomSerializer2 разница в скорости в 55 раз! И это МС продает как прорыв в работе с данными! По убывал бы. Причем вообще не ясно, что делает этот BinaryFormatter, так как известно, что DataSet всегда сериализуется в XML.
Скептики вроде DG должны заметить, что датасет не нуждается в универсальном сохранении графа объектов. Максимум что ему нужно сохранить свои таблицы... И это прекрасно делается с помощью ручной сериализации.
Попутно обнаружил серьезный недостаток. Дело в том, что Trantor не рассчитывал на то, что ячейки могут содержать DbNull. Мой вариант пока, что тоже не учитывать DbNull, но завтра допишу его шоб поддерживал. Запас по скорости таки есть.
Так же добавил в тесте сборку мусора (двойную, с ожиданием). Чтобы вообще не было намека на наложенку.
Традиционно вначале результаты (мой вариант называется DetaSetCustomSerializer2):
DataSetHandsSerializate
Serialization time elapsed: 381
Length is: 1 600 338
Loading time elapsed: 1 171
DetaSetCustomSerializer2
Serialization time elapsed: 100 !!!
Length is: 948 955 !!!
Loading time elapsed: 290 !!!
DataTable одинаковые!
BinaryFormatter
Serialization time elapsed: 3 715
Length is: 7 819 323 !!!! Это все потому, что реально в Датасете хранится XML!
Loading time elapsed: 16 103 !!!!
DataTable одинаковые!
XmlSerializer
Serialization time elapsed: 1 833
Length is: 10 059 102
Loading time elapsed: 7 371
DataTable одинаковые!
SoapFormatter
Serialization time elapsed: 2 854
Length is: 11 980 266
Loading time elapsed: 9 063
DataTable одинаковые!
using System;
using System.IO;
using System.Data;
namespace SerializeTest
{
class DetaSetCustomSerializer2
{
// Массив для перемапливания TypeCode на Type
// TypeCode это перечисление включающее константы для базовых типов.static Type[] _TypeMap;
// Статический констрктор. Нужен для инициализации _TypeMap.static DetaSetCustomSerializer2()
{
// TypeCode.DBNull и TypeCode.Empty пропущены, так как они
// по сути не являются типами.
_TypeMap = new Type[(int)TypeCode.String + 1];
_TypeMap[(int)TypeCode.Object] = typeof(Object);
_TypeMap[(int)TypeCode.Boolean] = typeof(Boolean);
_TypeMap[(int)TypeCode.Char] = typeof(Char);
_TypeMap[(int)TypeCode.SByte] = typeof(SByte);
_TypeMap[(int)TypeCode.Byte] = typeof(Byte);
_TypeMap[(int)TypeCode.Int16] = typeof(Int16);
_TypeMap[(int)TypeCode.UInt16] = typeof(UInt16);
_TypeMap[(int)TypeCode.Int32] = typeof(Int32);
_TypeMap[(int)TypeCode.UInt32] = typeof(UInt32);
_TypeMap[(int)TypeCode.Int64] = typeof(Int64);
_TypeMap[(int)TypeCode.UInt64] = typeof(UInt64);
_TypeMap[(int)TypeCode.Single] = typeof(Single);
_TypeMap[(int)TypeCode.Double] = typeof(Double);
_TypeMap[(int)TypeCode.Decimal] = typeof(Decimal);
_TypeMap[(int)TypeCode.DateTime] = typeof(DateTime);
_TypeMap[(int)TypeCode.String] = typeof(String);
}
public static void Serialize(Stream stream, DataSet ds)
{
BinaryWriter bw = new BinaryWriter(stream);
DataTableCollection tables = ds.Tables;
bw.Write(ds.DataSetName);
bw.Write(tables.Count);
foreach(DataTable dt in tables)
{ // Вообще-то foreach-и лучше на всякий пожанный избегать. Но мне было в лом.
DataColumnCollection columns = dt.Columns;
int iColCount = columns.Count;
TypeCode[] colTypeCodes = new TypeCode[iColCount];
//table name
bw.Write(dt.TableName);
//count columns
bw.Write(iColCount);
for(int i = 0; i < iColCount; i++)
{
DataColumn dc = columns[i];
// Получаем TypeCode для типа обрабатываемой колонки.
TypeCode tc = Type.GetTypeCode(dc.DataType);
// Запоминаем TypeCode колонки в соотвествующем массиве.
colTypeCodes[i] = tc;
bw.Write(dc.ColumnName);
// Записываем TypeCode как Int32. Можно было бы и сэкономить 3 байта. :)
bw.Write((Int32)tc);
// TODO: Нужно добавть проверку на DbNull !!!
}
///////////////////////////////////////////////////////////////
// add data
// count rows
bw.Write(dt.Rows.Count);
foreach(DataRow dr in dt.Rows)
{
for(int i = 0; i < iColCount; i++)
{
// Записываем данные ячейки.
// TODO: Нужно добавть проверку на DbNull !!!switch(colTypeCodes[i])
{ // Каждому типу соотвествует переопределенная фунция...case TypeCode.Boolean: bw.Write((Boolean)dr[i]); break;
case TypeCode.Char: bw.Write((Char)dr[i]); break;
case TypeCode.SByte: bw.Write((SByte)dr[i]); break;
case TypeCode.Byte: bw.Write((Byte)dr[i]); break;
case TypeCode.Int16: bw.Write((Int16)dr[i]); break;
case TypeCode.UInt16: bw.Write((UInt16)dr[i]); break;
case TypeCode.Int32: bw.Write((Int32)dr[i]); break;
case TypeCode.UInt32: bw.Write((UInt32)dr[i]); break;
case TypeCode.Int64: bw.Write((Int64)dr[i]); break;
case TypeCode.UInt64: bw.Write((UInt64)dr[i]); break;
case TypeCode.Single: bw.Write((Single)dr[i]); break;
case TypeCode.Double: bw.Write((Double)dr[i]); break;
case TypeCode.Decimal: bw.Write((Decimal)dr[i]); break;
case TypeCode.DateTime:
// Для DateTime приходится выпендриваться особым образом.
bw.Write(((DateTime)(dr[i])).ToFileTime());
break;
case TypeCode.String: bw.Write((String)dr[i]); break;
default:
// На всякий случай пробуем записать неопознанный тип
// виде строки.
bw.Write(dr[i].ToString());
break;
}
}
}
}
}
public static DataSet Deserialize( Stream stream )
{
BinaryReader br = new BinaryReader(stream);
// Считываем имя датасета и создаем его...
DataSet ds = new DataSet(br.ReadString());
int counTables = br.ReadInt32();
DataTable dt;
DataColumn dc;
DataRow dr;
for(int t = 0; t < counTables; t++)
{
// Имя дататэйбла тоже передается в качестве параметра конструктора.
dt = new DataTable(br.ReadString());
int iColCount = br.ReadInt32();
// В этом массив будут записаны TypeCode-ы для колонок DataTable-а.
TypeCode[] colTypeCodes = new TypeCode[iColCount];
// А в этот массив будут записаны типы (Type) колонок DataTable-а
// соотвествующие TypeCode-ам.
Type[] colTypes = new Type[iColCount];
for(int c = 0; c < iColCount; c++)
{
string colName = br.ReadString();
// Считываем TypeCode.
TypeCode tc = (TypeCode)br.ReadInt32();
// Помещаем TypeCode в массив для дальнейшего использования.
colTypeCodes[c] = tc;
// Получаем (через мап) тип соответсвующий TypeCode-у.
Type type = _TypeMap[(int)tc];
// Создаем колонку с полученым именем и типом.
dc = new DataColumn(colName, type);
dt.Columns.Add(dc);
}
int counRows = br.ReadInt32();
for(int r = 0; r < counRows; r++)
{
// Считываем данные.
dr = dt.NewRow();
for(int i = 0; i < iColCount; i++)
{
// TODO: Здесь нужно бы обрабатывать DbNull !!!switch(colTypeCodes[i])
{
case TypeCode.Boolean: dr[i] = br.ReadBoolean(); break;
case TypeCode.Char: dr[i] = br.ReadChar(); break;
case TypeCode.SByte: dr[i] = br.ReadSByte(); break;
case TypeCode.Byte: dr[i] = br.ReadByte(); break;
case TypeCode.Int16: dr[i] = br.ReadInt16(); break;
case TypeCode.UInt16: dr[i] = br.ReadUInt16(); break;
case TypeCode.Int32: dr[i] = br.ReadInt32(); break;
case TypeCode.UInt32: dr[i] = br.ReadUInt32(); break;
case TypeCode.Int64: dr[i] = br.ReadInt64(); break;
case TypeCode.UInt64: dr[i] = br.ReadUInt64(); break;
case TypeCode.Single: dr[i] = br.ReadSingle(); break;
case TypeCode.Double: dr[i] = br.ReadDouble(); break;
case TypeCode.Decimal: dr[i] = br.ReadDecimal(); break;
case TypeCode.DateTime:
dr[i] = DateTime.FromFileTime(br.ReadInt64());
break;
case TypeCode.String: dr[i] = br.ReadString(); break;
default:
dr[i] = Convert.ChangeType(br.ReadString(),
colTypeCodes[i]);
break;
}
}
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
}
return ds;
}
}
}
Тестовый код:
using System;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
namespace SerializeTest
{
class Class1
{
// Сравнивает два DataTablestatic bool CmpDataTables(DataTable dt1, DataTable dt2)
{
if(dt1.Rows.Count != dt1.Rows.Count)
return false;
if(dt1.Columns.Count != dt1.Columns.Count)
return false;
int iCols = dt1.Columns.Count;
DataRowCollection rows1 = dt1.Rows;
DataRowCollection rows2 = dt2.Rows;
int iRows = rows1.Count;
for(int r = 0; r < iRows; r++)
{
DataRow dr1 = rows1[r];
DataRow dr2 = rows2[r];
for(int i = 0; i < iCols; i++)
{
if(!dr1[i].Equals(dr2[i]))
return false;
}
}
Console.WriteLine("DataTable одинаковые!");
return true;
}
// Вызывает суровую уборку мусора. :)static void ClearMem()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
[STAThread]
static void Main(string[] args)
{
int start; // Используется для вычисления времени выполнения
DataSet ds = new DataSet("myDataSet");
DataTable dt = new DataTable("Table1");
dt.Columns.Add(new DataColumn("col0", typeof(Int32)));
dt.Columns.Add(new DataColumn("col1", typeof(string)));
dt.Columns.Add(new DataColumn("col2", typeof(DateTime)));
dt.Columns.Add(new DataColumn("col3", typeof(byte)));
DataRow dr;
for (int i = 0; i < 40000; i++)
{
dr = dt.NewRow();
dr[0] = i;
dr[1] = "2test" + i.ToString();
dr[2] = DateTime.Now;
dr[3] = (byte)i % 255;
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
// Стрим для сериализации через BinaryFormatter
MemoryStream msBf = new MemoryStream(1024);
// Стрим для ручной сериализации через DataSetHandsSerializate.
MemoryStream msBm1 = new MemoryStream(1024);
// Стрим для ручной сериализации через DetaSetCustomSerializer2.
MemoryStream msBm2 = new MemoryStream(1024);
// Стрим для сериализации через SoapFormatter
MemoryStream msSf = new MemoryStream(1024);
// Стрим для сериализации через XmlSerializer
MemoryStream msXml = new MemoryStream(1024);
BinaryFormatter bf = new BinaryFormatter();
SoapFormatter sf = new SoapFormatter();
DataSet dsLoaded;
ClearMem(); // Вызов GC чтобы небыло налаженки...
// Сериализация DataSetHandsSerializate
start = Environment.TickCount;
DataSetHandsSerializate.Serialize(msBm1, ds);
Console.WriteLine(
"\n DataSetHandsSerializate\n"
+ "Serialization time elapsed: {0,10:### ### ###}\n"
+ "Length is: {1,10:### ### ###}",
Environment.TickCount - start, msBm1.Length);
// Загрузка DataSetHandsSerializate
msBm1.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
dsLoaded = DataSetHandsSerializate.Deserialize(msBm1);
Console.WriteLine("Loading time elapsed: {0,10:### ### ###}",
Environment.TickCount - start);
CmpDataTables(dsLoaded.Tables[0], ds.Tables[0]);
ClearMem();
// Сериализация DetaSetCustomSerializer2
start = Environment.TickCount;
DetaSetCustomSerializer2.Serialize(msBm2, ds);
Console.WriteLine(
"\n DetaSetCustomSerializer2\n"
+ "Serialization time elapsed: {0,10:### ### ###}\n"
+ "Length is: {1,10:### ### ###}",
Environment.TickCount - start,msBm2.Length);
// Загрузка DetaSetCustomSerializer2
msBm2.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
dsLoaded = DetaSetCustomSerializer2.Deserialize(msBm2);
Console.WriteLine("Loading time elapsed: {0,10:### ### ###}",
Environment.TickCount - start);
CmpDataTables(dsLoaded.Tables[0], ds.Tables[0]);
ClearMem();
// Сериализация BinaryFormatter
start = Environment.TickCount;
bf.Serialize(msBf, ds);
Console.WriteLine(
"\n BinaryFormatter\n"
+ "Serialization time elapsed: {0,10:### ### ###}\n"
+ "Length is: {1,10:### ### ###}",
Environment.TickCount - start,msBf.Length);
// Загрузка BinaryFormatter
msBf.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
dsLoaded = (DataSet)bf.Deserialize(msBf);
Console.WriteLine("Loading time elapsed: {0,10:### ### ###}",
Environment.TickCount - start);
CmpDataTables(dsLoaded.Tables[0], ds.Tables[0]);
ClearMem();
// Сериализация XmlSerializer
start = Environment.TickCount;
XmlSerializer serializer =
new XmlSerializer(typeof(DataSet));
serializer.Serialize(msXml, ds);
Console.WriteLine(
"\n XmlSerializer\n"
+ "Serialization time elapsed: {0,10:### ### ###}\n"
+ "Length is: {1,10:### ### ###}",
Environment.TickCount - start, msXml.Length);
// Загрузка XmlSerializer
msXml.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
dsLoaded = (DataSet)serializer.Deserialize(msXml);
Console.WriteLine("Loading time elapsed: {0,10:### ### ###}",
Environment.TickCount - start);
CmpDataTables(dsLoaded.Tables[0], ds.Tables[0]);
ClearMem();
// Сериализация SoapFormatter
start = Environment.TickCount;
sf.Serialize(msSf, ds);
Console.WriteLine(
"\n SoapFormatter\n"
+ "Serialization time elapsed: {0,10:### ### ###}\n"
+ "Length is: {1,10:### ### ###}",
Environment.TickCount - start, msSf.Length);
// Загрузка SoapFormatter
msSf.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
dsLoaded = (DataSet)sf.Deserialize(msSf);
Console.WriteLine("Loading time elapsed: {0,10:### ### ###}",
Environment.TickCount - start);
CmpDataTables(dsLoaded.Tables[0], ds.Tables[0]);
Console.ReadLine();
}
}
}
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Сериализация в дотнете 2 - самопальный датасет
под бинарный вид... отладку и тесты... > > Результаты показались настолько интересными, что решил создать новую тему. >
Еще на 100 сообщений? WOW!
А уж рассказы про то, что BinaryFormatter медленнее, чем Soap это совсем смешно. Провести кучу тестов и не сказать почему он в этом тесте оказался медленне?
Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно, то тогда зачем DataSet использовать?
И хорошо-бы каждый тест оформить в отдельном методе, вызывать его как минимум несколько раз, а потом интерполировать значения. При этом несколько первых результатов можно и отбросить.
Posted via RSDN NNTP Server 1.5 beta
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, VladD2, Вы писали:
VD>На всякий пожарный сделал проверку качества сериализации путем загрузки данных в другой DataSet и сравнения с исходным. Вариант Trantor-а не прошел проверку. Оказалось, что дата записанная в стринг по средствам ToString() и считанная обратно теряет точность. Так что вариант со строковой сериализацией нужно еще дописывать. Если вообще нужна строковая сериализация. Ведь разница в скорости почти 4 раза, и в размерах данных примерно в 1.7 раза.
Согласен с тобой, отправляем мой датасет на свалку истории
VD>За одно измерил время загрузки. Результаты оказались дико интересным! Гляньте на результаты BinaryFormatter-а!
Вот тут мне все предлагали то Sleep поставить, то GC.Collect, а ты попробуй местами поменять форматеры, прогони тест 2-3 раза и посмотри на результаты, у меня почему-то всегда (и при Sleep и GC.Collect) первый форматер приблизительно 1 секунду дольше работал... Я уже списал это на мой тормознтый комп (P3-700-128Мб), но может и у других также...
VD>Попутно обнаружил серьезный недостаток. Дело в том, что Trantor не рассчитывал на то, что ячейки могут содержать DbNull. Мой вариант пока, что тоже не учитывать DbNull, но завтра допишу его шоб поддерживал. Запас по скорости таки есть.
Я об этом подумал, но не проверил Скорее всего есть еще не учтеные моменты....
... << RSDN@Home 1.0 beta 6a >>
В жизни мало быть умным, надо еще быть не дураком.
Re[2]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно, то тогда зачем DataSet использовать?
А что за такие оригинальные значения?
... << RSDN@Home 1.0 beta 6a >>
В жизни мало быть умным, надо еще быть не дураком.
Re[3]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, Trantor, Вы писали:
TK>Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно, то тогда зачем DataSet использовать?
T>А что за такие оригинальные значения?
см. DataRow.Item Property (DataColumn, DataRowVersion)
перед тем, как писать тесты хорошо-бы представлять себе назначение DataSet.
А то, что получается: Взяли автомобиль, заменили двигатель внутреннего сгорания на педальную тягу и после этого сравниваем его с велосипедом...
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно, то тогда зачем DataSet использовать?
Здравствуйте, AndrewVK, Вы писали:
TK>Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно, то тогда зачем DataSet использовать?
AVK>А еще там не сериализуется схема.
Кстати, а почему они стали делать сериализацию целиком, а написали XmlReader/XmlWriter по двоичным данным?
(а то обсуждение большое, перечитывать некогда...)
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>см. DataRow.Item Property (DataColumn, DataRowVersion) TK>перед тем, как писать тесты хорошо-бы представлять себе назначение DataSet.
Написано перед тестом: T>Вообщем по совету Влада решил написать самопальный сериализатор датасета, функционал его выполнен не полностью (не хватает связей между таблицами,ключевых полей и может еще чего...),но для большинства случаев он сгодится.
По поводу Original значений, единственное что я нашел по этому поводу в MSDN вот это After calling the DataRow object's AcceptChanges method, the Original value becomes identical to the Current value. Т.е. получается что пока мы не вызовем AcceptChanges у таблицы или строчки, в датасете хранится как оригинальное значение, так и текущее, после вызова AcceptChanges оригинальные значения не остаются... Все попытки получить эти значения(оригинальные) при сериализации датасета в XML у меня провалились... Поэтому если несложно напиши пример или кинь ссылку на то как это все должно выглядить в сериализованом виде.
... << RSDN@Home 1.0 beta 6a >>
В жизни мало быть умным, надо еще быть не дураком.
Re[3]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>Кстати, а почему они стали делать сериализацию целиком, а написали XmlReader/XmlWriter по двоичным данным? TK>(а то обсуждение большое, перечитывать некогда...)
Здравствуйте, AndrewVK, Вы писали:
AVK>Что, и все референсы тоже?
Под референсами ты понимаешь System.Data/System.Data, Version 1.0.3300.0 ....?
Если это, то его и стандартный сериализатор датасета недобавляет, а добавляет форматер...
... << RSDN@Home 1.0 beta 6a >>
В жизни мало быть умным, надо еще быть не дураком.
Re[2]: Сериализация в дотнете 2 - самопальный датасет
TK>И хорошо-бы каждый тест оформить в отдельном методе, вызывать его как минимум несколько раз, а потом интерполировать значения. При этом несколько первых результатов можно и отбросить.
Обоими руками поддерживаю. Так, кстати, и возможные интерференции с GC нивелируются, и разброс/погрешность измерений оценить можно.
... << RSDN@Home 1.0 beta 6a >>
Re[5]: Сериализация в дотнете 2 - самопальный датасет
T> Поэтому если несложно напиши пример или кинь ссылку на то как это все должно выглядить в сериализованом виде.
WriteXml, с параметром DiffGram.
Наверное, и сериализация эти "оригинальные значения" должна записывать/считывать — по крайней мере я видел там именно DiffGram-формат.
Также в DataSet есть специальный метод для выделения только изменившихся данных — вроде Clone, но возвращает только изменения. Такое обычно используется для отправки изменений на сервер, или для приёма изменений с сервера.
... << RSDN@Home 1.0 beta 6a >>
Re[6]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>А уж рассказы про то, что BinaryFormatter медленнее, чем Soap это совсем смешно.
Можешь смеяться. Такие резулттаты и у АВК.
TK>Провести кучу тестов и не сказать почему он в этом тесте оказался медленне?
Чтобы сказать почему. Нужно иметь приличный профайлр для дотнета. У меня его нет. Я попытался скомпилировать бинари-форматер от CLI, но он настолько завязан в mscorlib, что выдрать его от туда почти невозможно.
TK>Кстати — в вашем тесте не видно, что DataSet могут быть не только текущие значения, но и оригинальные. Если это не нужно,
Во многих случаях ненужно. Но нет этго скорее потому, что 1) забыли, 2) и так роботенка нехилая.
TK>то тогда зачем DataSet использовать?
Дык потому-что это самый простой и удобный способ передать данные полученные из БД с сервера клиенту. И потому-что для датасета относительно легко написать рукопашную сериализацию. Со структурами все будет намного сложнее. Скорость же их сериализации дотнетными форматерами ненамного выше чем датасета.
TK>И хорошо-бы каждый тест оформить в отдельном методе, вызывать его как минимум несколько раз, а потом интерполировать значения.
Можно попробовать.
TK>При этом несколько первых результатов можно и отбросить.
А от чего же отбрасывать. Интересны и те, и те результаты.
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>Кстати, а почему они стали делать сериализацию целиком, а написали XmlReader/XmlWriter по двоичным данным? TK>(а то обсуждение большое, перечитывать некогда...)
Они это мы или парни из МС? И что значит "написали XmlReader/XmlWriter по двоичным данным?"?
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, TK, Вы писали:
TK>см. DataRow.Item Property (DataColumn, DataRowVersion) TK>перед тем, как писать тесты хорошо-бы представлять себе назначение DataSet.
Ну, кое-кто все же знает как жта штука устроена. Ну, а на вопрос я отвтил выше. Времени небыло и нужды особой.
TK>А то, что получается: Взяли автомобиль, заменили двигатель внутреннего сгорания на педальную тягу и после этого сравниваем его с велосипедом...
Я бы это дело с конем педальным сравнил. Так как для передачи данных по сети он подходит так же как педальный конь для поездок в гости.
Будет время доведу серализацию до ума. Заметно медленнее или больше по объему она не станет. Не будет версий — не будет и особого увеличения объема данных и времени на их сериализацию.
В любом случае деже в таком виде датасет становится прекрасным средством передачи данных по сети. Во многих случаях этого достаточно.
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.