3

I've been messing around with the default interface implementations. Figured you have to de a downcast to the interface type to use a default method implementation. I also found a bunch of notes on another syntax, I can't find if this is already included or not, I did find "decisions" on how it's going to look, it doesn't work however. Am I doing it wrong or is this new syntax not included yet?

Somewhat related but doesn't answer my question: Calling C# interface default method from implementing struct without boxing

Notes on the base<>/base() syntax: https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-11-14.md#default-interface-implementations

Microsoft's page on the proposal: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods

class D : IA, IB, IC
{
                  //Notice the use of base() right here.
    void IA.M() { base(IB).M(); }
}

So say we need INotifyPropertyChanged on some object. We can now have a SetField implementation as default on an interface:

public interface INotify : INotifyPropertyChanged
{
    void InvokePropertyChanged(string propertyName);

    bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        INotify thing = (INotify)this;

        if (propertyName == null)
        {
            throw new ArgumentException($"{nameof(propertyName)} is null. PropertyChangedEventHandler will not be fired correctly.");
        }

        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        InvokePropertyChanged(propertyName);
        return true;
    }
}

Implementing it needs a downcast (((INotify)this).SetField), using base(INotify) would be preferred here.

public class Thing : INotify
{
    public string A
    {
        get => _a;
        //Need an explicit cast here. Can't figure out how to use base syntax.
        set => ((INotify)this).SetField(ref _a, value);
    }
    private string _a;

    public event PropertyChangedEventHandler PropertyChanged;

    public void InvokePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
c2619813
  • 31
  • 1
  • This was released. Usage is explained in several blogs, the official docs (not just the proposal) and the relevant tag, `default-interface-member`. No downcasts are involved - default members use the explicit interface syntax, ie you have to cast to the interface to get its members. This avoids conflicts between members with the same interface in multiple interfaces – Panagiotis Kanavos Sep 26 '19 at 08:43
  • @PanagiotisKanavos I've linked to multiple docs. None of the examples work. Can you provide a working example from one of those blogs you talk about? – c2619813 Sep 26 '19 at 08:45
  • -> ie you have to cast to the interface to get its members -> So the `base` syntax was NOT released? Because you have to cast to the interface. – c2619813 Sep 26 '19 at 08:49
  • You linked to the old proposals, not the current tutorials, docs and blog posts. Check the tag's info as it contains a lot of information that does work. Check the questions under that tag too, you'll find for example that [the cast doesn't box](https://stackoverflow.com/questions/57827493/calling-c-sharp-interface-default-method-from-implementing-struct-without-boxing) – Panagiotis Kanavos Sep 26 '19 at 08:49
  • That's explicit interface calling, not a downcast. It's already available since C# 1.0. And unlike casting, it won't box and hence won't allocate – Panagiotis Kanavos Sep 26 '19 at 08:50
  • Now, what is the *actual* question? How to create a trait that implements INotifyPropertyChanged ? You can simplify the code a lot, eg by using pattern matching and get rid of the null checks. The `InvokePropertyChanged` looks something that should be done by the interface too, it's only the event that needs to be implemented by the concrete class – Panagiotis Kanavos Sep 26 '19 at 09:01
  • They are just cracking down on using the feature inappropriately. It was meant to be a refactoring aid, adding members to an interface can be quite painful since it requires changing every class that implements it. Easy to get stuck badly if you don't have the source. But if you can modify the class then you're expected to implement the member and not rely on the default. They had to change the CLR to support the feature, non-zero odds that it is expensive. – Hans Passant Sep 26 '19 at 09:20
  • @PanagiotisKanavos I played around with this idea but you can't invoke the event from the interface. Have you figured a way to do that? – fstam Sep 26 '19 at 09:53
  • 1
    The base syntax is discussed [here](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#base-interface-invocations-closed) and multiple decisions are documented there but it doesn't seen to be in the language. – fstam Sep 26 '19 at 10:02

0 Answers0