C# 克隆 EventHandler

7

我有一个包含多个事件处理程序的类(以及其他内容):

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

我希望能够在GameObject中添加一个Clone()函数,它将返回它所调用的对象的精确副本。我尝试过这样做:

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

但是,看起来它使clone.BeginStep指向与this.BeginStep相同的对象,而不是制作副本。那么,我如何复制EventHandler对象?


这对您有帮助吗?https://dev59.com/H3VD5IYBdhLWcg3wHn6d - Akhil
5个回答

10

您不必担心这个问题。 EventHandler<EventArgs> 对象是不可变的,因此任何一个对象中监听器列表的更改都会导致该对象获得一个新的包含更新调用列表的 EventHandler<EventArgs> 实例。这种更改不会出现在另一个 GameObject 中。


5
尝试使用 += 运算符添加它。我甚至不知道可以分配事件。
clone.Initialize += this.Initialize;

此外,所有委托都是不可变的值类型,因此您无需担心它们指向相同的对象。当您执行上述操作时,整个委托将被复制(克隆,如果您愿意)。

委托是不可变的引用类型,确切地说。 - nawfal

1

这取决于你的事件是否委托给了在GameObject类中定义的方法,还是委托给了其他观察者类实例。

如果事件是在你的GameObject类中定义的方法中处理的,并且你希望克隆中的事件由克隆实例中的方法处理,你可以使用反射来获取原始事件处理程序中的方法信息,使用克隆实例和方法名称创建一个新的委托,然后将新的委托分配为克隆事件处理程序。

    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;
    }

如果事件在不同的类中处理,则您无需做任何事情,但是原始实例和克隆实例的所有事件通知都将具有相同的处理程序。 如果这不是您想要的,则需要在克隆后更改事件委托。

0

你不需要克隆事件,就像你不需要克隆源对象的任何方法一样。当你克隆时,你只需要复制成员/属性值。


0

你需要做类似于深度克隆对象的操作。

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);
    }
}

你的类需要可序列化。

编辑:正如我所说,它是基于我链接的代码,并且我匆忙地回答了问题。应该更仔细地检查一下。


Clone<GameObject>?从技术上讲是有效的,但非常误导。要么将其泛型化,并称其为Clone<T>,要么不要使其成为泛型,并删除泛型参数。 - ShdNx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接