1

here's an interface I use.

public interface IPresentism {

    public abstract bool isPresent { get; }

    public virtual bool isAbsent => !isPresent;
}

isPresent is abstract so the interface user has to implement it.

Interface also carries a handy negation of that, isAbsent, which is implemented, and virtual so it should be added to all subclasses it's mixed in with (actually it's never overridden but whatever, remove 'overide' from isAbsent doesn't change anything). Try using IPresentism then..

public class tester : IPresentism {

    public bool isPresent => true;

    public bool checkAbsentVisible =>
        this.isAbsent;  // fails
}

Error is

Error CS1061 'tester' does not contain a definition for 'isAbsent' and no accessible extension method 'isAbsent' accepting a first argument of type 'tester' could be found.

C#8 is supposed to support these "You can now add members to interfaces and provide an implementation for those members" https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#default-interface-methods. Perhaps it really is methods not properties, try that:

public interface IPresentism {

    public abstract bool isPresent(); // { get; }

    public virtual bool isAbsent() => !isPresent();
}


public class tester : IPresentism {

    public bool isPresent() => true;

    public bool checkAbsentVisible =>
        this.isAbsent();  // nope again
}

Same error. What am I misunderstanding?

user3779002
  • 566
  • 4
  • 17

1 Answers1

3

The rule is that default Methods declared in an interface are only available if you cast the object to the interface type.

The reasons behind this are both technical and theoretical, and explained here. Here is a quote, to which I added some emphasis:

That cast from SampleCustomer to ICustomer is necessary. The SampleCustomer class doesn't need to provide an implementation for ComputeLoyaltyDiscount; that's provided by the ICustomer interface. However, the SampleCustomer class doesn't inherit members from its interfaces. That rule hasn't changed. In order to call any method declared and implemented in the interface, the variable must be the type of the interface, ICustomer in this example.

The effect is that this does not compile:

public bool checkAbsentVisible => this.isAbsent();

While this is OK:

public bool checkAbsentVisible => ((IPresentism)this).isAbsent();

And so is this:

public bool checkAbsentVisible => (this as IPresentism).isAbsent();
Peter B
  • 22,460
  • 5
  • 32
  • 69
  • Very helpful, accepted. Do you know if casting is safe; will the compiler reject it statically. I've just tried it and it appears to statically accept a ridiculous cast, which would mean a runtime error, implying using these is opening a risky type hole. Is that right? – user3779002 Dec 27 '21 at 20:15
  • I should explain, I've used casts like "a as b" and had the compiler warn me statically that 'a' can never be of type 'b', so it seemed reasonable that something likewise should be done here. – user3779002 Dec 27 '21 at 21:33