views:

24

answers:

1

When you have an object that provides events and you use a deepclone (serialisation) approach to cloning the object, how do you do it when there are events on the object that are actually attached.

If my object declares an event, but nothing is attached then object can be cloned without issue.

BUT if the object has had events attached, then the serialisation fails. All the associated classes have their Serializable attribute applied (except the Form1, which is being used for testing).

So in the following example, if i call Create(true) then the Clone fails (see exception at the end).

If I call Create(false) then it works properly

The example code is contrived, but hopefully it will demonstrate what I'm trying to do.

private void Create(bool useEvent)
{
    mRab = new Rabbits();

    if (useEvent) mRab.Changed += new Rabbits.ChangedEventHandler(ChangedRabbits);

    Rabbit  r;
    r = new Rabbit();
    r.Monkeys.Add(new Monkey("Test"));
    mRab.Add(r);

    Rabbits r2;
    r2 = DeepClone(mRab);
}

public static T DeepClone<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        var f = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        f.Serialize(ms, obj);
        ms.Position = 0;
        return (T)f.Deserialize(ms);
    }
}

The exception when Cloning when the event is attached. System.Runtime.Serialization.SerializationException: Type 'CSharpClonetest.Form1' in Assembly 'CSharpClonetest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) at CSharpClonetest.Form1.DeepClone[T](T obj) in C:\Development\Spikes\TestDeepCloneEvent\CSharpClonetest\Form1.cs:line 30

A: 

Add [field: NonSerialized] to the event declaration.

SLaks
so once you do this, how do you get the events rebound, or do you need to do something like this? public Rabbits Clone() { Rabbits r; r = DeepClone(this); r.Changed = this.Changed; return r; }
Paul Farry
@Paul: Yes, you do.
SLaks
:-( just wish this project had been written in C# my life would have been easier because VB doesn't have that ability (afaik)
Paul Farry