2013-02-05 40 views
0

我正在編寫基本上具有選擇功能的自定義,具有TypeNameSelectMethod屬性。自定義數據源控件上的數據序列化

來自TypeName類的數據將保存在由參數值和ContextName的哈希索引的文件中。這意味着,每當GridView請求數據源並給出相同的參數值時,控件就會找到相應的文件並從那裏加載數據。實際上,每個不同的參數值組合都會生成一個帶有數據的新文件。

時進行處理,並從數據庫中檢索到的數據時間過長,並不需要是實時的用戶此功能可以在某些情況下,我們有很大的幫助(它總是從最後一天)。

我遇到的主要困難是序列化來自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); 
} 

哪能一般序列化/反序列化的選擇方法結果爲XML?

更新:

我試着用System.Web.UI.LosFormatter,以序列化/反序列化的數據。它使用IEnumerable實例完成了兩個操作,但我必須將Serializable屬性放在實體上。但是,從XMLSerializer的文件中檢索數據時,我注意到性能上的顯着差異。 System.Web.UI.LosFormatter在我的特定測試(4MB文件)上進行反序列化時速度降低了4倍。與XMLSerializer壽相比,數據文件的大小是其一半。所以,對我而言,XMLSerializer仍然是最佳選擇。

UPDATE2:

把我的使用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<,>"。 有什麼辦法可以讓這項工作?

+0

由於y你在ASP.NET上下文中工作,你可以使用LosFormatter而不是XmlSerializer(如果你不需要數據是人類可讀的)。優點是它非常自動化並且具有「網絡感知」功能,並且支持的類型與Web控件屬性一致。看到這裏:http://www.west-wind.com/weblog/posts/2006/Oct/13/LosFormatter-for-easy-Serialization –

+0

@ Simon Mourier,感謝您的評論,更新了與內容相關的答案LosFormatter。 –

+0

我認爲XmlSerializer速度更快的原因是因爲Xml序列化是在臨時彙編中自動編譯的,順便說一句,這就是爲什麼它不是非常靈活/自動/多功能。 –

回答

0

那麼,正如你已經發現的,你不能序列化一個接口......這麼說,你可能能夠解決這一點,仍然是「在黑暗中」關於實際的對象類型:

首先,任何的IEnumerable可以通過Cast/ToArray組合被transmogrified到一個數組

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); 

變種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)); 
+0

感謝您的回答。我嘗試了你的代碼,但是在'GetEnumerable'方法中,我返回了'List ','Dummy'是一些只有Name屬性的測試類。它返回錯誤'類型WebApp.Page + Dummy不是預期的。在ser.Serialize'行使用XmlInclude或SoapInclude屬性來指定靜態未知的類型。你看,我只是這樣做來模擬我們擁有的共同語境。 –

+0

啊,是的,幾乎忘了 - 我用了'XmlSerializer'的錯誤重載 - 我將編輯答案。 @ Mt.Schneiders好吧,試試這個版本。 – JerKimball

+0

謝謝@JerKimball。你能告訴我反序列化XML數據的代碼嗎?因爲我在嘗試檢索數據時沒有'allContainedTypes',所以假設'DataSourceControl'本身在調用'SelectMethod'之前驗證了XML的存在。 –

相關問題