【问题标题】:How can I implement a Clone method on an abstract class without using MemberwiseClone?如何在不使用 MemberwiseClone 的情况下在抽象类上实现 Clone 方法?
【发布时间】:2021-04-20 18:26:01
【问题描述】:

我有一个这样定义的抽象基类:

public abstract class BaseItem: INotifyPropertyChanged, ICloneable
{
    // Various Properties...

    public event public event PropertyChangedEventHandler PropertyChanged;

    public object Clone()
    {
        var clone = (BaseItem)MemberwiseClone();
        return clone;
    }
}

派生类继承并使用基类的 Clone 方法,因此它们不必实现自己的 Clone 方法(加上一些额外的、不相关的原因)。

通常,此代码按预期工作。唯一的问题是有一个不需要的副作用。因为我使用 MemberwiseClone 来克隆实例,所以引用类型是浅拷贝的,不幸的是其中包括事件。因此,任何已订阅原始实例事件的对象也将订阅克隆实例上的事件。这就是问题所在。

有没有什么方法可以使用 BaseItem.Clone 方法克隆 BaseItem 派生类的实例而不也克隆事件?

【问题讨论】:

  • 不幸的是 MemberwiseClose 是一个 extern 所以很难复制+粘贴+修改它来做你想做的事。我建议您致电MemberwiseClone,然后使用this technique 删除事后的事件处理程序。
  • 只要clone.PropertyChanged = null;。如果您拥有事件处理程序,则无需采用@JohnWu 提到的复杂方式。
  • 是的,我希望能够完全不复制事件处理程序,而不是事后删除它们,但如果前者确实不可能,那么我猜后者将不得不工作。 @ckuri 的解决方案非常有效。谢谢。
  • 您需要每个派生类用正确的复制语义覆盖Clone。要获得DerivedClass 的返回值,您可以使用Curiously Recurring Template Pattern public abstract class BaseItem<T> where T : BaseItem<T>

标签: c# cloning icloneable


【解决方案1】:

正如@JohnWu 在评论中提到的,对我有用的解决方案是将事件处理程序设置为 null 以删除其所有订阅者。

public abstract class BaseItem: INotifyPropertyChanged, ICloneable
{
    // Various Properties...

    public event PropertyChangedEventHandler PropertyChanged;

    public object Clone()
    {
        var clone = (BaseItem)MemberwiseClone();
        clone.PropertyChanged = null;
        return clone;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    • 2017-02-17
    • 2021-07-02
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多