22

serializable 属性でマークされていないオブジェクトを永続化する必要があります。オブジェクトは、変更できないサードパーティのライブラリからのものです。

ファイルシステムなどの永続的な場所に保存する必要があるため、最適な解決策はオブジェクトをファイルにシリアル化することですが、シリアル化可能としてマークされていないため、それは単純なソリューションではありません。

これはかなり複雑なオブジェクトで、他のオブジェクトのコレクションも保持しています。

これを解決する方法について何か意見はありますか?このコードは本番環境では決して実行されないため、ほとんどすべてのソリューションとパフォーマンスで問題ありません。

4

5 に答える 5

9

XmlSerializerタイプがパブリックなどの場合、最初に試すのに役立つ場合があります

それが失敗した場合、protobuf-net の v2 (進行中、ソースからビルドする必要がありますが、私がお手伝いできます) は、属性のないオブジェクトで動作するため、制御できないタイプに理想的です。何を含めるかを指定するだけです ( DSL 経由)。v2 コードは完全ではありませんが、コレクションなどを含む最も一般的なシナリオをカバーしています (不完全な作業は主にコールバックと列挙型です)。

于 2010-04-07T20:33:25.220 に答える
5

リフレクションを使用してオブジェクト グラフをたどってオブジェクトを永続化する再帰的なメソッドを作成することもできます。これらのオブジェクトのいずれかが、管理されていないリソースまたはシステム リソースへの参照を保持しているかどうかは誰にもわかりません。もし私がこのようなことをするなら、私は.GetFields(...)タイプの方法を選びます。

別のアイデア...

開発をスピードアップするためだけにこれを行っている場合は、それらのクラスを独自のアダプター クラスでラップしないでください。これにより、サードパーティのライブラリを独自の簡略化されたモック クラスに置き換えることができ、後で置き換えて再利用する可能性が高くなります。

それは病気です...これは思ったより簡単でした。(これは機能しますが...サードパーティのクラスをラップすることを検討してください。)

public static class Tools
{
    public static XElement AsXml(this object input)
    {
        return input.AsXml(string.Empty);
    }
    public static XElement AsXml(this object input, string name)
    {
        if (string.IsNullOrEmpty(name))
            name = input.GetType().Name;

        var xname = XmlConvert.EncodeName(name);

        if (input == null)
            return new XElement(xname);

        if (input is string || input is int || input is float /* others */)
            return new XElement(xname, input);

        var type = input.GetType();
        var fields = type.GetFields(BindingFlags.Instance |
                                    BindingFlags.NonPublic)
                         .Union(type.GetFields(BindingFlags.Instance |
                                               BindingFlags.Public));

        var elems = fields.Select(f => f.GetValue(input)
                                        .AsXml(f.Name));

        return new XElement(xname, elems);
    }
    public static void ToObject(this XElement input, object result)
    {
        if (input == null || result == null)
            throw new ArgumentNullException();

        var type = result.GetType();
        var fields = type.GetFields(BindingFlags.Instance |
                                    BindingFlags.NonPublic)
                         .Union(type.GetFields(BindingFlags.Instance |
                                               BindingFlags.Public));

        var values = from elm in input.Elements()
                     let name = XmlConvert.DecodeName(elm.Name.LocalName)
                     join field in fields on name equals field.Name
                     let backType = field.FieldType
                     let val = elm.Value
                     let parsed = backType.AsValue(val, elm)
                     select new
                     {
                         field,
                         parsed
                     };

        foreach (var item in values)
            item.field.SetValue(result, item.parsed);            
    }

    public static object AsValue(this Type backType,
                                      string val,
                                      XElement elm)
    {
        if (backType == typeof(string))
            return (object)val;
        if (backType == typeof(int))
            return (object)int.Parse(val);
        if (backType == typeof(float))
            return (float)int.Parse(val);

        object ret = FormatterServices.GetUninitializedObject(backType);
        elm.ToObject(ret);
        return ret;
    }
}
public class Program
{
    public static void Main(string[] args)
    {
        var obj = new { Matt = "hi", Other = new { ID = 1 } };
        var other = new { Matt = "zzz", Other = new { ID = 5 } };
        var ret = obj.AsXml();
        ret.ToObject(other);
        Console.WriteLine(obj); //{ Matt = hi, Other = { ID = 1 } }
        Console.WriteLine(other); //{ Matt = hi, Other = { ID = 1 } }
    }
}
于 2010-04-07T20:33:54.853 に答える
3

これはあなたがそれを行うことができる1つの方法です:

http://www.codeproject.com/KB/dotnet/Surrogate_Serialization.aspx

それを示すmsdnリンクは次のとおりです。

http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

于 2010-04-07T20:32:03.007 に答える
2

あなたの使い方がやり過ぎかどうかはわかりませんが、最近db4oをいじっています。IObjectContainer.Store(object) を呼び出すだけで任意のオブジェクトを保持し、軽量でファイルベースです。インストールは必要ありません。

まだ問題はありません。

于 2010-04-07T20:31:15.273 に答える