2

Why can I not do the following?

public class TestClass : TestInterface
{
    public ClassX Property { get; private set; }
}

public interface TestInterface
{
    InterfaceX Property { get; }
}

public interface InterfaceX
{

}

public class ClassX : InterfaceX
{

}

The TestInterface Property is readonly, thus can only return InterfaceX as per the contract.

However, I get this compiler error:

'TestClass' does not implement interface member 'TestInterface.InterfaceX'. 'TestClass.InterfaceX' cannot implement 'TestInterface.InterfaceX' because it does not have the matching return type of 'InterfaceX'.

It does not have the matching type but it has a subclass of that type.

payo
  • 4,501
  • 1
  • 24
  • 32
Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207

2 Answers2

5

I don't know the spec offhand, but I'm sure there's one that explicitly states that return types must match exactly for interface implementations. The closest I can find is 13.4.4:

For purposes of interface mapping, a class member A matches an interface member B when:

  • A and B are methods, and the name, type, and formal parameter lists of A and B are identical.
  • A and B are properties, the name and type of A and B are identical, and A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation).

If "type" above means "return type" that would indicate that the return type cannot change.

You could, however, change the return type and explicitly implement the interface with the right return type:

public class TestClass : TestInterface
{
    public ClassX InterfaceX { get; private set; }
    InterfaceX TestInterface.InterfaceX { get { return InterfaceX; } }
}

UPDATE

According to Eric Lippert it seems to be a CLR limitation, not just a C# one.

Community
  • 1
  • 1
D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • The explixit reason is that the interface exposes a reduced set of the class functionality but I need it all at the class level to implement the logic – Ignacio Soler Garcia Mar 12 '14 at 19:21
  • Then I would either use a _different_ property or use explicit implementation. – D Stanley Mar 12 '14 at 19:26
  • Note that Im only implementing the get, not the set like in the referenced question. – Ignacio Soler Garcia Mar 12 '14 at 19:43
  • @SoMoS well, you ARE implementing `set` - it's just `private`. There's no `set` accessor on the interface so you _can't_ implement it publicly. – D Stanley Mar 12 '14 at 19:54
  • "Only using get" is a moot point, the same specification rule applies. – payo Mar 12 '14 at 19:59
  • @D Stanley: but you cannot do anything wrong with that design. You cannot use the interface to pass a type than cannot be assigned to the concrete class like the referenced question shows. – Ignacio Soler Garcia Mar 12 '14 at 20:01
  • 1
    @SoMoS true, but that is a limitation of the language spec. Take it up with Lippert :) Also, see my answer :) You might like it. – payo Mar 12 '14 at 20:02
  • Yeah, I do. I was arguing about the referendlced question only. Your approach seems good to me. – Ignacio Soler Garcia Mar 12 '14 at 20:08
  • 1
    @SoMoS: So to clarify: in the linked question the poster wants something that (1) is not typesafe, and (2) even if it were typesafe, requires return type covariance. Your question is "ok, now I've made it typesafe, so that eliminates the first objection, so what's the problem?" The problem is that the second objection still stands: there is no return type covariance in C# or the CLR. Not because it is unsafe; it is perfectly safe. But because it's never been a high enough priority to implement, and all the compiler would do is implement the same code you could. – Eric Lippert Mar 12 '14 at 20:11
  • 1
    @SoMoS Think about it from a caller's perspective - if I call `InterfaceX` do I get a `ClassX` that I can call more methods on or a `InterfaceX` that I can't? That's why the _explicit_ implementation allows both - the caller can specify _which_ method to bind to (and the compiler doesn't have to guess). It's also (I assume) why methods can't be overloaded based on return type - how does the compiler know which one to bind to? – D Stanley Mar 12 '14 at 20:13
0

You mentioned that you want to expose a reduced set but you want all the functionality internal to the class -- that's not what you want to use an interface for. An interface should only be about your reduced set contract, not also magically function as a full set internally, not without another helper property.

But, there is a way around this limitation while still communicating the contract a little.

interface IExpose<IToolType> where IToolType : ITool
{
  IToolType Handler { get; set; }
}

class Expose : IExpose<Tool>
{
  public Tool Handler { get; set; }
}

interface ITool
{
}

class Tool : ITool
{
}
payo
  • 4,501
  • 1
  • 24
  • 32