6

I have a class with multiple EventHandlers (among other things):

public GameObject
{
    public event EventHandler<EventArgs> Initialize;
    public event EventHandler<EventArgs> BeginStep;
    ....
}

I want to be able to add a Clone() function to GameObject, which returns an exact duplicate of the object it was called on. I tried doing it like this:

    public GameObject Clone()
    {
        var clone = new GameObject()
        {
            Initialize = this.Initialize,
            BeginStep = this.BeginStep,
        };
    }

But, it appears that it is making clone.BeginStep point to the same object as this.BeginStep instead of making a copy. So, how do I make a copy of an EventHandler object?

Entity
  • 7,972
  • 21
  • 79
  • 122

5 Answers5

9

You don't need to worry about that. The EventHandler<EventArgs> object is immutable so any change in the list of listeners in either object will cause that object to get a new EventHandler<EventArgs> instance containing the updated invocation list. This change will not be present in the other GameObject.

Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
4

Try adding it with the += operator. I didn't even know it was possible to assign an event.

clone.Initialize += this.Initialize;

Also, all delegates are immutable value types, therefore you don't have to worry about them pointing to the same object - when you an operation like above, the whole delegate is copied (cloned, if you will).

ShdNx
  • 3,172
  • 5
  • 40
  • 47
1

It depends on whether your events are delegating to methods defined in the GameObject class or whether they delegate to to some other observer class instance.

If the events are handled in methods defined in your GameObject class and you want events in the clone to be handled by methods in your clone instance, you can get use reflection to get the method info from the original event handlers, create a new delegate using the cloned instance and the method name, and then assign the new delegate as the cloned event handler.

    public GameObject Clone()
    {
        var clone = new GameObject();
        foreach (var target in this.Initialize.GetInvocationList())
        {
            var mi = target.Method;
            var del = Delegate.CreateDelegate(
                          typeof(EventHandler<EventArgs>), clone, mi.Name);
            clone.Initialize += (EventHandler<EventArgs>)del;
        }
        return clone;
    }

If the events are handled in a different class, then you don't need to do anything, but all event notifications for both the original instance and cloned instance willhave the same handlers. If that's not what you want then you'll need to change the event delegates after you clone.

lee_greco
  • 31
  • 1
  • 3
0

You don't need to clone the events, just like you don't need to clone any methods of the source object. When you clone, all you really need to duplicate are the member/property values.

Jacob
  • 77,566
  • 24
  • 149
  • 228
0

You'll want to do something akin to what was posted on Deep cloning objects

public static GameObject Clone(GameObject source)
{
    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(GameObject);
    }

    IFormatter formatter = new BinaryFormatter();
    Stream stream = new MemoryStream();
    using (stream)
    {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (GameObject)formatter.Deserialize(stream);
    }
}

Your class will need to be serializable.

EDIT: As I said, it was based off of the code I linked to, and I hurried to give the answer. Should've checked it a little closer.

Community
  • 1
  • 1
CassOnMars
  • 6,153
  • 2
  • 32
  • 47
  • Clone? That's technically valid, but it's very misleading. Either make it generic, and call it Clone, or don't make it generic, and drop the generic parameter. – ShdNx Jun 09 '11 at 17:19