自定义DataSourceControl上的数据序列化
本文关键字:数据 序列化 DataSourceControl 自定义 | 更新日期: 2023-09-27 17:57:56
我正在编写一个自定义DataSourceControl
,它基本上具有与普通ObjectDataSource
一样的Select功能,具有TypeName
和SelectMethod
属性。
来自TypeName类的数据将保存在由参数值的哈希和ContextName索引的文件中。这意味着,每当GridView请求DataSource并给出相同的参数值时,控件都会找到相应的File并从中加载数据。事实上,每个不同的参数值组合都会生成一个带有数据的新文件。
在某些情况下,当数据需要很长时间才能从数据库中处理和检索,并且不需要对用户实时(总是从最后一天开始)时,此功能可能非常有用。
我遇到的主要困难是序列化来自SelectMethod的数据。因为我只知道返回类型将是IEnumerable
的一个实例。我使用XMLSerializer
来保存和检索文件中的数据内容,但在尝试序列化时,它会给我一个错误Cannot serialize interface
。
这是执行SelectMethod并执行序列化部分的基本代码:
//Gets the select type
Type selectType = Type.GetType(TypeName);
//Gets the select method
MethodInfo selectMethod = selectType.GetMethod(SelectMethod, BindingFlags.Instance | BindingFlags.Public);
//Creates a new instance of the TypeName class
object selectInstance = Activator.CreateInstance(selectType);
//Executes the select method
object selectResult = selectMethod.Invoke(selectInstance, parameters);
IEnumerable list = (IEnumerable)selectResult;
//Create a serializer
XmlSerializer serializer = new XmlSerializer(typeof(IEnumerable));
//Writes to the XML file
using (XmlWriter writer = XmlWriter.Create(filePath))
{
serializer.Serialize(writer, list);
}
我会使用此代码来反序列化:
//Creates the XML File
XmlSerializer deserializer = new XmlSerializer(typeof(IEnumerable));
IEnumerable list = null;
//Reads from the XML file
using (XmlReader writer = XmlReader.Create(filePath))
{
list = (IEnumerable) deserializer.Deserialize(writer);
}
如何将Select Method结果序列化/反序列化为XML?
更新:
我尝试使用System.Web.UI.LosFormatter
对数据进行序列化/反序列化。它使用IEnumerable实例执行这两个操作,但我必须在实体上放置Serializable
属性。然而,在从文件中检索数据时,我注意到与XMLSerializer
相比,性能有显著差异。System.Web.UI.LosFormatter
在我的特定测试(4MB文件)上的反序列化速度慢了4倍。与XMLSerializer
tho相比,数据文件的大小将是其大小的一半。所以,对我来说,XMLSerializer
仍然是最好的选择。
更新2:
尝试使用ServiceStack JsonSerializer
进行一个简单的测试,代码如下:
List<Dummy> dummies = new List<Dummy>();
dummies.Add(new Dummy() { Name = "name" });
dummies.Add(new Dummy() { Name = "name1" });
dummies.Add(new Dummy() { Name = "name2" });
IEnumerable enumerableThing = dummies;
string filePath = Path.Combine(Server.MapPath("~/App_Data"), "data2.json");
using (StreamWriter writer = new StreamWriter(filePath))
{
JsonSerializer.SerializeToWriter<IEnumerable>(enumerableThing, writer);
}
using (StreamReader reader = new StreamReader(filePath))
{
enumerableThing = JsonSerializer.DeserializeFromReader<IEnumerable>(reader);
}
它确实可以串行化,但当尝试DeserializeFromReader时,它会给我错误"Type System.Collections.IEnumerable is not of type IDictionary<,>"
。有什么办法让我做这件事吗?
好吧,正如您已经发现的,您不能序列化接口。。。也就是说,你可能能够解决这个问题,但仍然对实际的对象类型"一无所知":
首先,任何IEnumerable都可以通过Cast
/ToArray
组合转换为数组
var enumerableThing = Foo.GetEnumerable();
var asArray = enumerableThing.Cast<object>().ToArray();
第二,"已知类型"的数组是可串行化的
var allContainedTypes = asArray.Select(x => x.GetType()).Distinct().ToArray();
var ser = new XmlSerializer(asArray.GetType(), allContainedTypes);
var ser=新的XmlSerializer(asArray.GetType())
var sb = new StringBuilder();
using(var sw = new StringWriter(sb))
using(var xw = XmlWriter.Create(sw))
ser.Serialize(xw, asArray);
sb.ToString().Dump();
或者,加在一起:
void Main()
{
var enumerableThing = Foo.GetEnumerable();
var asArray = enumerableThing.Cast<object>().ToArray();
var allContainedTypes = asArray.Select(x => x.GetType()).Distinct().ToArray();
var ser = new XmlSerializer(asArray.GetType(), allContainedTypes);
var sb = new StringBuilder();
using(var sw = new StringWriter(sb))
using(var xw = XmlWriter.Create(sw))
ser.Serialize(xw, asArray);
sb.ToString().Dump();
}
public class Foo
{
public static IEnumerable GetEnumerable()
{
return new[] { 1, 2, 3, 4, 5, 6, 7 };
}
public static IEnumerable GetEnumerable2()
{
return new object[] { "1", 2, "bob", 4, null, 6, 7 };
}
}
哦,这产生了格式:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfAnyType
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<anyType xsi:type="xsd:int">1</anyType>
<anyType xsi:type="xsd:int">2</anyType>
<anyType xsi:type="xsd:int">3</anyType>
<anyType xsi:type="xsd:int">4</anyType>
<anyType xsi:type="xsd:int">5</anyType>
<anyType xsi:type="xsd:int">6</anyType>
<anyType xsi:type="xsd:int">7</anyType>
</ArrayOfAnyType>
编辑:反序列化确实会带来一些问题——然而,你可以做一些类似于的事情
// Least common denominator...
object[] tempResult;
var assemblyStuffIsFrom = Assembly.GetExecutingAssembly();
var allSerializableTypes = assemblyStuffIsFrom
.GetTypes()
.Where(t => t.GetCustomAttributes(typeof(SerializableAttribute), true).Any())
// TODO: add as much filtering as you can here to help trim down the set
.ToArray();
var hope = new XmlSerializer(typeof(object[]), allSerializableTypes);
using(var sr = new StringReader(sb.ToString()))
using(var xr = XmlReader.Create(sr))
tempResult = ((object[])hope.Deserialize(xr));