Clone objects events.

S

Ste

Good morning,
what can be the best way to clone an object with events ?

This because I have made a deep copy of my object and added new event
handlers but events are fired from the original instance, not in cloned
instance.

Thank you.
Stefano.
 
M

Marc Gravell

If it is your own object, then simply copy the delegate. Copying the
events of a type you don't own is much tricker, and probably not a good
idea - not least because the average caller won't expect to be targetted
by something they didn't subscribe to - which could lead to unexpected
memory leaks* and bugs from not finding "sender" in an expected list.

Marc

*=not a true leak - just the side-effect of one object keeping another
alive.
 
J

Jon Skeet [C# MVP]

Good morning,
what can be the best way to clone an object with events ?

This because I have made a deep copy of my object and added new event
handlers but events are fired from the original instance, not in cloned
instance.

I suspect that without a concrete example we could run into
misunderstandings very quickly. Could you post a short but complete
program demonstrating the problem? See http://pobox.com/~skeet/csharp/complete.html
for what I mean by that.

For what it's worth, in my experience cloning tends to be fraught with
issues, and I suspect that introducing delegates into the mix will
only make it more so.

Jon
 
S

Ste

Hi Marc, can you explain more about copying the delegate ? Do you have a
little sample ?

Thank you.
Stefano.

Marc Gravell ha scritto:
 
S

Ste

Hi Peter,
I have not cloned delegates, simply added new delegates to object cloned.

Thank you.
Stefano.

Peter Duniho ha scritto:
 
S

Ste

It's a bit complex to write a short sample.

I can explain more about :

class 1 : CopyActivity : INotifyPropertyChanged
Properties:
string Source
string Destination
bindinglist<string> DirsExcluded
bindinglist<string> FilesExcluded
bool IsModified (true when a property or the content of a
bindinglist changes)

Methods:
object Clone()
{ ..deep copy and add new eventhandlers... }
void ListChanged()
{ IsModified = true }
Initializer :
public CopyActivity()
{
DirsExcluded = new bindinglist<string>;
DirsExcluded.ListChanged +=
new ListChangedEventHandler(ListChanged);
}

class 2 : Profile
Properties:
string ProfileName
bool IsModified
BindingList<CopyActivity> Activities

Thank you.
Stefano.


Jon Skeet [C# MVP] ha scritto:
 
M

Marc Gravell

It's a bit complex to write a short sample.

Unfortunately, that is usually when a short sample is the most valuable!
If it is complex, we are certainly going to get the wrong end of the
stick just through trying to descibe it, so a sample is invaluable... it
doesn't have to do the same thing - just indicate where it is coming
unstuck.

The sample posted doesn't really indicate what is failing, or what you
want to do differently, etc..

Marc
 
S

Ste

Ok, I try to write only concerning sections :

This is the clone method, I need to add event handlers only to cloned
object.

public CopyActivity DeepClone()
{
CopyActivity Cloned = new CopyActivity();
using (MemoryStream ms =
new MemoryStream ())
{
BinaryFormatter bf =
new BinaryFormatter ();
bf.Serialize (ms, this);
ms.Position = 0;
Cloned = (CopyActivity)bf.Deserialize (ms);
Cloned.Name = "CLONED";
AddEvents (Cloned);
}
return Cloned;
}

With this method I add eventhandlers to cloned object.

public void AddEvents(CopyActivity Ca)
{
Ca.DirsExcluded.ListChanged +=
new ListChangedEventHandler(ListChanged);
Ca.FilesExcluded.ListChanged +=
new ListChangedEventHandler (ListChanged);
Ca.FileSpecsExcluded.ListChanged +=
new ListChangedEventHandler (ListChanged);
Ca.FileSpecsIncluded.ListChanged +=
new ListChangedEventHandler (ListChanged);
}

Unique event handler for all events because they all do same thing.

private void ListChanged(object sender, ListChangedEventArgs e)
{
IsModified = true;
}

This is class initializer, no eventhandlers are added.

public CopyActivity()
{
_active = true;
_isModified = false;
_dirsExcluded = new BindingList<string> ();
_filesExcluded = new BindingList<string> ();
_fileSpecsExcluded = new BindingList<string> ();
_fileSpecsIncluded = new BindingList<string> ();
}

If I use these methods ListChanged is fired only in object contained in
collection and not in clone.

Thank you.
Stefano.

P.s. Sorry for my english !


Marc Gravell ha scritto:
 
J

Jon Skeet [C# MVP]

Ok, I try to write only concerning sections :

You're still making the example more complicated than it needs to be.

Just show a class with a single event, and another class which
subscribes to it. Then do whatever cloning you'd do, and show what's
wrong. It doesn't need to achieve any of the same real goals as your
application code. The thing is, it's not immediately clear from your
description whether it's the event subscriber or the publisher which
is being cloned. A short but complete example would really help there.

Jon
 
S

Ste

Ok, this is a runnable sample, if you try it can view that listchanged
on clone is fired by original object and not from cloned.

Thank you.
Stefano.

//----------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace ConsoleApplication1
{

[Serializable]
public class class1
{
private string _name;
private bool _isModified;
private BindingList<string> _list;

public string Name
{
get { return _name; }
set { _name = value; }
}

public bool IsModified
{
get { return _isModified; }
set { _isModified = value; }
}

public BindingList<string> List
{
get { return _list; }
set { _list = value; }
}

public class1()
{
List = new BindingList<string> ();
_isModified = false;
_name = "NORMAL";
}

public class1 DeepClone()
{
class1 Cloned = new class1 ();
using (MemoryStream ms =
new MemoryStream ())
{
BinaryFormatter bf =
new BinaryFormatter ();
bf.Serialize (ms, this);
ms.Position = 0;
Cloned = (class1)bf.Deserialize (ms);
Cloned.List.ListChanged += new ListChangedEventHandler (
ListChanged);
Cloned.Name = "CLONED";
}
return Cloned;
}

private void ListChanged(object sender,
ListChangedEventArgs e)
{
_isModified = true;
}
}

class Program
{
static void Main(string[] args)
{
class1 ClsTest = new class1 ();
Console.WriteLine ("Normal - IsModified : " +
ClsTest.IsModified.ToString ());
ClsTest.List.Add ("TEST");
Console.WriteLine ("Normal - IsModified : " +
ClsTest.IsModified.ToString ());

class1 Cloned = ClsTest.DeepClone ();
Cloned.IsModified = false;

Cloned.List.Add ("PROVA");
Console.WriteLine ("Cloned - IsModified : " +
Cloned.IsModified.ToString ());

Console.ReadKey ();
}
}
}
//----------------------------------------------------------------------------------------


Jon Skeet [C# MVP] ha scritto:
 
M

Marc Gravell

I suspect the problem is the following:

Cloned.List.ListChanged += new ListChangedEventHandler (
ListChanged);

There is an implicit "this" here - it should be:

Cloned.List.ListChanged += new ListChangedEventHandler (
Cloned.ListChanged);

Marc
 
M

Marc Gravell

No problem; for the record, I wouldn't have a public "set" for list (or
you could get into a big sticky mess) - but that might just have been in
the short example ;-p

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top