0

I have an abstract base class defined like this:

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

    public event public event PropertyChangedEventHandler PropertyChanged;

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

The derived classes inherit and use the base class's Clone method so that they don't have to implement their own Clone methods (plus some additional, irrelevant reasons).

Generally, this code works as intended. The only problem is that there is an unwanted side effect. Because I'm using MemberwiseClone to clone the instance, reference types are shallow copied, which unfortunately includes events. So any objects that have subscribed to events on the original instance will also be subscribed to events on the clone instance. This is the problem.

Is there any way that I can make a clone of an instance of a BaseItem-derived class using the BaseItem.Clone method without also cloning events?

oaky_afterbirth
  • 125
  • 3
  • 15
  • Unfortunately `MemberwiseClose` is an `extern` so it'd be pretty hard to copy+paste+modify it to do what you want. I suggest you call `MemberwiseClone` and then use [this technique](https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-an-event) to remove the event handlers post hoc. – John Wu Jan 15 '21 at 19:10
  • 2
    Just do `clone.PropertyChanged = null;`. If you own the event handler you don’t need to go the complicate way @JohnWu mentioned. – ckuri Jan 15 '21 at 19:25
  • Yeah, I was hoping to be able to not copy the event handlers at all, rather than have to remove them afterwards, but if the former is indeed not possible, then I guess the latter will have to work. @ckuri 's solution works perfectly. Thanks. – oaky_afterbirth Jan 15 '21 at 19:52
  • You need every derived class to override `Clone` with the correct copy semantics. To get a return value of `DerivedClass` you can use the [Curiously Recurring Template Pattern](https://ericlippert.com/2011/02/02/curiouser-and-curiouser/) `public abstract class BaseItem where T : BaseItem` – Charlieface Jan 16 '21 at 21:24

1 Answers1

0

As @JohnWu mentioned in the comment, the solution that worked for me was to set the event handler to null to remove all its subscribers.

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

    public event PropertyChangedEventHandler PropertyChanged;

    public object Clone()
    {
        var clone = (BaseItem)MemberwiseClone();
        clone.PropertyChanged = null;
        return clone;
    }
}
oaky_afterbirth
  • 125
  • 3
  • 15