0

私は、DataSourceControl基本的にSelect機能が通常どおりObjectDataSourceに機能し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);
}

Select Methodの結果を一般的にXMLにシリアル化/逆シリアル化するにはどうすればよいですか?

アップデート:

System.Web.UI.LosFormatterデータのシリアル化/逆シリアル化にを使用してみました。IEnumerableインスタンスで両方のアクションを実行しましたがSerializable、エンティティに属性を設定する必要がありました。XMLSerializerただし、ファイルからデータを取得する場合と比較して、パフォーマンスに大きな違いがあることに気付きました。System.Web.UI.LosFormatter私の特定のテスト(4MBファイル)での逆シリアル化では4倍遅くなりました。XMLSerializerデータファイルは、 thoと比較して半分のサイズになります。だから、私にとっては、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<,>"。これを機能させる方法はありますか?

4

1 に答える 1

0

すでに発見したように、インターフェイスをシリアル化することはできません...とはいえ、これを回避しても、実際のオブジェクトタイプについて「暗闇の中で」いることができるかもしれません。

まず、任意の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 = 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 に答える