1

Is there a reason why a method with a more specific type cannot implement an interface with a less specific one?

public interface IInterface<out T>
{
    T GetValues();
}

public class Class : IInterface<object>
{
    public Class GetValuesSubType() => null;

    //public object GetValues() => GetValuesSubType();

    // This won't compile:
    public Class GetValues() => null;
}

As the method returning the same values is perfectly valid code with only upcasting.

Is it a by design or is it just a "missing" feature?

EDIT:

It might actually be supported in C#7: https://github.com/dotnet/roslyn/issues/357

Stefano d'Antonio
  • 5,874
  • 3
  • 32
  • 45
  • Yes it breaks [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle). This should be closed as a dupe, I don't have the question that has been already answered on here... – Erik Philips Mar 11 '16 at 23:19
  • 1
    How is this braking Liskov's principle? "if S is a subtype of T, then objects of type T may be replaced with objects of type S". And it actually compiles and doesn't generate any runtime error if we use a rounting method. – Stefano d'Antonio Mar 11 '16 at 23:23
  • Because your method `GetValues()` can only return a class (horribly named) `Class`. Any derived type of `Class` cannot return `object`, only `Class`. – Erik Philips Mar 11 '16 at 23:24
  • 1
    @ErikPhilips The Wikipedia article you linked to mentions that this ("Covariance of return types in the subtype") is allowed by LST. – svick Mar 11 '16 at 23:27
  • 1
    Consider the case where your *sigh* `Class` class has fifty methods, each of which return some type that inherits from `object` (e.g.: all of them), and takes zero parameters in its signature. Which of them is the implementation of `IInterface`? – Preston Guillot Mar 11 '16 at 23:29
  • @svick Exactly, contravariance in return types is perfectly Liskov compiant... Erik: Feel free to edit the post with a name that tickles your fancies, although absolutely irrelevant. – Stefano d'Antonio Mar 11 '16 at 23:29
  • I can't find the article, but [Eric Lippert](https://blogs.msdn.microsoft.com/ericlippert/) mentioned that C# does not support Covariance for return types or something (maybe that it never will)... – Erik Philips Mar 11 '16 at 23:31
  • @Preston It won't compile in any case if the methods have the same name, even if it's not implementing the inferface, unless I am misunderstanding your answer. – Stefano d'Antonio Mar 11 '16 at 23:32
  • 1
    BTW, you're code isn't *Covariance of return types in the subtype* which would be to `return new Class()` you're actually changing the signature of the interface, but not in the interface, that is the issue. – Erik Philips Mar 12 '16 at 00:02
  • @Uno Of course you're right, I wasn't thinking =\ – Preston Guillot Mar 12 '16 at 02:59

1 Answers1

0

I think this is because you declare in interface that you want to return 'object'. In this case GetValues should return 'object' not Class.

Assume we have Class public class Class : IInterface with Class as template argument not object as you wanted.

Then IL code looks like this :

.method public final hidebysig newslot virtual 
    instance class Namespace.Class GetValues () cil managed 

We can see "hidebysig" here. It is translated to "hide by name-and-signature" thus if you would have another signature in IInterface and another in Class as a result you would have no override, just adding new method with the same name but different argument vector - we do not want that.

Also, inherited class would be abstract because of an empty slot for interface's declaration.

Interesting fact : As far as I know all methods in C# are hidebysig by definition.

MaLiN2223
  • 1,290
  • 3
  • 19
  • 40
  • "But remember that we can not have the same name for two methods with identic arument vector and different return type." Why not? I tried writing such methods IL, and compiling them using ilasm and verifying using peverify and everything was fine. – svick Mar 11 '16 at 23:40
  • I was thinking about creating raw C# code without using dynamic object creation. I deleted this sentence since it was not entirely true - you are absolutely right – MaLiN2223 Mar 11 '16 at 23:43