C# Interfaces – Implementing Multiple Disparate Interfaces in a Single Base Class

cinheritanceinterfaces

(This is probably a dupe, but if so I haven't seen it yet, although it may be Best practice for encapsulating a parameter that requires multiple interfaces to be implemented, but that question doesn't answer my situation)

Normally I don't care that c# only has single inheritance, but I have run into something where I think that multiple inheritance actually would improve things, and I can't see a clean way to do it with single inheritance.

This comes about from wanting to support both INotifyPropertyChanged and INotifyDataErrorInfo in a re-usable manner. These interfaces are independent and require a non-trivial amount of code to support them, and up until now I have only considered INotifyPropertyChanged and have a system of:

public class MyPropertyChangedBase : INotifyPropertyChanged
{
   // re-usable code to support INotifyPropertyChanged
}

public MyViewModel : MyPropertyChangedBase
{
  // various WPF bound properties that notify the UI on change
}

However, now I want to implement INotifyDataErrorInfo in a re-usable manner, but the code to support this interface is totally orthogonal and unrelated to the INotifyPropertyChanged code. So ideally they should be implemented in unrelated base classes and use multiple inheritance for my view model. EG (note this is NOT valid c# code – it is only for highlighting an 'idealistic' situation):

public class MyPropertyChangedBase : INotifyPropertyChanged
{
   // re-usable code to support INotifyPropertyChanged
}

public class MyErrorChangedBase : INotifyDataErrorInfo
{
   // re-usable code to support INotifyDataErrorInfo
}

public MyViewModel : MyPropertyChangedBase, MyErrorChangedBase
{
  // various WPF bound properties that notify the UI on change and error
}

(Note that I can't use composition to fix this, as I would need to map from the components to the public instances of the interface elements, which just shifts the problem and doesn't solve it)

So what I seem to be left with is having either the INotifyPropertyChanged code rely on the INotifyDataErrorInfo code or vice versa. EG

public class MyPropertyChangedBase : INotifyPropertyChanged
{
   // re-usable code to support INotifyPropertyChanged
}

public class MyPropertyAndErrorChangedBase : MyPropertyChangedBase , INotifyDataErrorInfo
{
   // re-usable code to support INotifyDataErrorInfo
}

public MyViewModel : MyPropertyAndErrorChangedBase
{
  // various WPF bound properties that notify the UI on change and error
}

This reliance of one independent class on another doesn't sit well with me. So is there a cleaner way to do it? Or am I stuck with it?


Finally, I do recognize that realistically you would not implement INotifyDataErrorInfo without first having implemented INotifyPropertyChanged, so the reliance of one class on the other may be a pragmatic tradeoff. But I am still trying to find the cleanest way of doing this.

Best Answer

As Greg has already mentioned, your two interfaces relate to the View. More specifically, they both relate to ViewModel<->View interactions. So, having one class implement both is not a big deal.

I do, however, understand that you might want to evolve the behaviour of each interface implementation independently, so how about this composition-based approach:

public abstract class MyPropertyChangedBase : INotifyPropertyChanged
{
    // re-usable code to support INotifyPropertyChanged
}

public abstract class MyErrorChangedBase : INotifyDataErrorInfo
{
    // re-usable code to support INotifyDataErrorInfo
}

public abstract class ViewModelBase : MyPropertyChangedBase
{
    // classic VM
}

public abstract class ErrorAwareViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
    private readonly MyPropertyChangedBase changeNotifier;
    private readonly MyErrorChangedBase errorNotifier;

    public ErrorAwareViewModelBase(MyPropertyChangedBase changeNotifier, MyErrorChangedBase errorNotifier)
    {
        this.changeNotifier = changeNotifier;
        this.errorNotifier = errorNotifier;
    }

    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
    {
        add
        {
            this.changeNotifier.PropertyChanged += value;
        }

        remove
        {
            this.changeNotifier.PropertyChanged -= value;
        }
    }

    bool INotifyDataErrorInfo.HasErrors => this.errorNotifier.HasErrors;

    event EventHandler<DataErrorsChangedEventArgs> INotifyDataErrorInfo.ErrorsChanged
    {
        add
        {
            this.errorNotifier.ErrorsChanged += value;
        }

        remove
        {
            this.errorNotifier.ErrorsChanged -= value;
        }
    }

    IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
    {
        return this.errorNotifier.GetErrors(propertyName);
    }
}
Related Topic