0

我正在编写一个自定义DataSourceControl,它将基本上具有 Select 功能,就像正常工作一样ObjectDataSource,具有 aTypeNameSelectMethod属性。

来自 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<,>"。有什么办法可以使这项工作?

4

1 回答 1

0

好吧,正如您已经发现的那样,您无法序列化接口......也就是说,您可能能够解决这个问题并且仍然对实际对象类型“一无所知”:

Cast首先,任何 IEnumerable 都可以通过/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 = new 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));
于 2013-02-08T00:08:57.810 回答