我最近需要将数据表序列化为 JSON。我现在仍然使用 .Net 2.0,因此我无法在 .Net 3.5 中使用 JSON 序列化器。我想这肯定是以前做过的,所以我上网查了一下found http://www.codeproject.com/KB/aspnet/ASPNET_DataTable_to_JSON.aspx a number http://www.dennydotnet.com/post/A-DataTable-Serializer-for-ASPNET-AJAX.aspx of 不同的 http://schotime.net/blog/index.php/2008/07/27/dataset-datatable-to-json/ options https://web.archive.org/web/20200204000610/http://geekswithblogs.net/shahed/archive/2008/03/22/120709.aspx。其中一些依赖于额外的库,我在这里很难推动它。其他需要先转换为List<Dictionary<>>
,这似乎有点尴尬和不必要。另一个将所有值视为字符串。由于某种原因,我无法真正支持其中任何一个,所以我决定推出自己的,发布在下面。
从阅读中你可以看到//TODO
评论,有些地方不完整。该代码已经在此处投入使用,因此它在基本意义上确实“有效”。它不完整的地方是我们知道我们的生产数据当前不会命中它的地方(数据库中没有时间跨度或字节数组)。我在这里发帖的原因是我觉得这可以更好一点,并且我希望帮助完成和改进这段代码。欢迎任何意见。
请注意,此功能已内置于 .Net 3.5 及更高版本中,因此今天使用此代码的唯一原因是您仍受限于 .Net 2.0。即便如此,JSON.Net 已经成为此类事情的首选库。
public static class JSONHelper
{
public static string FromDataTable(DataTable dt)
{
string rowDelimiter = "";
StringBuilder result = new StringBuilder("[");
foreach (DataRow row in dt.Rows)
{
result.Append(rowDelimiter);
result.Append(FromDataRow(row));
rowDelimiter = ",";
}
result.Append("]");
return result.ToString();
}
public static string FromDataRow(DataRow row)
{
DataColumnCollection cols = row.Table.Columns;
string colDelimiter = "";
StringBuilder result = new StringBuilder("{");
for (int i = 0; i < cols.Count; i++)
{ // use index rather than foreach, so we can use the index for both the row and cols collection
result.Append(colDelimiter).Append("\"")
.Append(cols[i].ColumnName).Append("\":")
.Append(JSONValueFromDataRowObject(row[i], cols[i].DataType));
colDelimiter = ",";
}
result.Append("}");
return result.ToString();
}
// possible types:
// http://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype(VS.80).aspx
private static Type[] numeric = new Type[] {typeof(byte), typeof(decimal), typeof(double),
typeof(Int16), typeof(Int32), typeof(SByte), typeof(Single),
typeof(UInt16), typeof(UInt32), typeof(UInt64)};
// I don't want to rebuild this value for every date cell in the table
private static long EpochTicks = new DateTime(1970, 1, 1).Ticks;
private static string JSONValueFromDataRowObject(object value, Type DataType)
{
// null
if (value == DBNull.Value) return "null";
// numeric
if (Array.IndexOf(numeric, DataType) > -1)
return value.ToString(); // TODO: eventually want to use a stricter format. Specifically: separate integral types from floating types and use the "R" (round-trip) format specifier
// boolean
if (DataType == typeof(bool))
return ((bool)value) ? "true" : "false";
// date -- see https://weblogs.asp.net/bleroy/dates-and-json
if (DataType == typeof(DateTime))
return "\"\\/Date(" + new TimeSpan(((DateTime)value).ToUniversalTime().Ticks - EpochTicks).TotalMilliseconds.ToString() + ")\\/\"";
// TODO: add Timespan support
// TODO: add Byte[] support
//TODO: this would be _much_ faster with a state machine
//TODO: way to select between double or single quote literal encoding
//TODO: account for database strings that may have single \r or \n line breaks
// string/char
return "\"" + value.ToString().Replace(@"\", @"\\").Replace(Environment.NewLine, @"\n").Replace("\"", @"\""") + "\"";
}
}
Update:
现在已经很旧了,但我想指出有关此代码如何处理日期的一些信息。我当时使用的格式是有意义的,因为注释网址中的确切原理是这样的。然而,该理由包括以下内容:
老实说,JSON Schema 确实通过将字符串“子类型化”为日期文字来解决这个问题,但这仍在进行中,并且在实现任何重大采用之前还需要一段时间。
好吧,时间已经过去了。今天,只需使用ISO 8601 https://en.wikipedia.org/wiki/ISO_8601日期格式。我不会费心去改变代码,因为真的:这已经很古老了。就去使用 JSON.Net 吧。