2

バックグラウンド

VB.NET で作成したビジネス オブジェクトのコピーを作成しようとしています。ICloneable インターフェイスを実装し、Clone 関数で、BinaryFormatter を使用してオブジェクトをシリアル化し、関数から返される別のオブジェクトに逆シリアル化して、オブジェクトのコピーを作成します。

シリアル化しようとしているクラスは、クラス内に含まれる子オブジェクトと共に「シリアル化可能」としてマークされています。

次のようなコードを記述して、clone メソッドが機能することをテストしました。

Dim obj as New Sheep()
Dim dolly as Sheep = obj.Clone()

この時点ですべて正常に動作します。

問題

サード パーティ コントロールから継承するカスタム Windows フォーム コントロールがあります。このカスタム コントロールには基本的に、複製したいオブジェクトが含まれています (このオブジェクトは最終的にサード パーティ コントロールにフィードするため)。

Windowsフォームコントロール内にオブジェクトのクローンを作成して、変更をキャンセルしてオブジェクトを変更前の状態に戻すオプションを使用しながら、ユーザーがプロパティを操作できるようにしたいと考えています。ユーザーが変更を開始する前にオブジェクトのコピーを取り、それを保持して、キャンセルを押したときに準備できるようにしたいと思います。

私の考えは、次の行に沿ってコードを書くことです。

Dim copy as Sheep = MyControl.Sheep.Clone()

次に、ユーザーが のプロパティを操作できるようにしますMyControl.Sheep。ただし、これを実行しようとすると、clone メソッドは次のような例外をスローします。

アセンブリ 'My_Assembly_Info_Here' のタイプ 'MyControl' は、シリアル化可能としてマークされていません

このエラーは、 を呼び出した時点でスローされますBinaryFormatter.Serialize(stream,Me)

MyControlオブジェクトのコピーを返すメソッドを作成し、最初MyControl.Sheepに別の変数に割り当ててから変数を複製しようとしましたが、何も機能していないようです。ただし、オブジェクトの新しいインスタンスを直接作成して複製することは問題なく機能します。

私が間違っているところはありますか?

解決

マークの答えは、これについて正しい方向に私を向けるのに役立ちました. Rocky Lhotka の このブログ投稿では、問題とその解決方法について説明しています。

4

3 に答える 3

2

UI がサブスクライブしているイベントはありますか? データ バインディングの場合は {Foo}Changed イベント、またはおそらく INotifyPropertyChanged? イベント バッキング フィールドを [NonSerialized] としてマークする必要がある場合があります (または、属性は VB で表示されます - 私は C# の人です...)。フィールドのようなイベント (つまり、追加/削除のない省略された構文) を使用している場合は、イベント全体を [フィールド: NonSerialized] でマークします (これも VB に変換します)。

于 2008-10-03T13:35:08.400 に答える
0

サードパーティのライブラリでは、何かがシリアライズ可能とマークされていない場合、正当な理由でシリアライズすべきではありませんが、多くの場合、開発者が単純にそれを含めなかったため、シリアライズできません。リフレクションを使用して、コントロールのパブリック プロパティのコピーを作成し、キャンセル時にその状態を反映されたバージョンに戻すことができます。このアプローチにはパフォーマンスへの影響がありますが、UI 層で作業しているため、あまり心配する必要はないと思います。この方法でエラーが発生しないとは限りません。パブリック プロパティは必ずしもクラスの状態全体を表すとは限らず、一部のプロパティを設定すると副作用が生じる可能性があります (そうすべきではありませんが、コードを記述していないため、ILDasm を実行して確認するか、最善の結果を期待してください)。

さらに、プロパティのすべての型がシリアライズ可能であるとは限りません。その場合、それらの型 (および場合によってはそれらの型のプロパティ) のシリアライゼーション ルーチンを手動で記述する必要があります。

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    public class NonSerializableSheep
    {
        public NonSerializableSheep() { }

        public string Name { get; set; }
        public int Id { get; set; }
        // public read only properties can create a problem
        // with this approach if another property or (worse)
        // a group of properties sets it
        public int Legs { get; private set; }

        public override string ToString()
        {
            return String.Format("{0} ({1})", Name, Id);
        }
    }

    public static class GhettoSerializer
    {
        // you could make this a factory method if your type
        // has a constructor that appeals to you (i.e. default 
        // parameterless constructor)
        public static void Initialize<T>(T instance, IDictionary<string, object> values)
        {
            var props = typeof(T).GetProperties();

            // my approach does nothing to handle rare properties with array indexers
            var matches = props.Join(
                values,
                pi => pi.Name,
                kvp => kvp.Key,
                (property, kvp) =>
                    new {
                        Set = new Action<object,object,object[]>(property.SetValue), 
                        kvp.Value
                    }
            );

            foreach (var match in matches)
                match.Set(instance, match.Value, null);
        }
        public static IDictionary<string, object> Serialize<T>(T instance)
        {
            var props = typeof(T).GetProperties();

            var ret = new Dictionary<string, object>();

            foreach (var property in props)
            {
                if (!property.CanWrite || !property.CanRead)
                    continue;
                ret.Add(property.Name, property.GetValue(instance, null));
            }

            return ret;
        }
    }

    public class Program
    {
        public static void Main()
        {
            var nss = new NonSerializableSheep
            {
                Name = "Dolly",
                Id = 12
            };

            Console.WriteLine(nss);

            var bag = GhettoSerializer.Serialize(nss);

            // a factory deserializer eliminates the additional
            // declarative step
            var nssCopy = new NonSerializableSheep();
            GhettoSerializer.Initialize(nssCopy, bag);

            Console.WriteLine(nssCopy);

            Console.ReadLine();

        }
    }
}
于 2008-10-03T13:35:46.887 に答える
0

明らかな質問ですが、Sheep オブジェクトから MyControl への参照がないことを確信していますか? それはオブジェクトかリストか何かですか?この場合、これがビジネス オブジェクトの複製を妨げている原因です。

可能性が高い候補は、.Parentまたは.Tagプロパティです。

于 2008-10-03T13:14:18.473 に答える