Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why restricting return type for method and property inheritance so that descendants are not allowed?

Tags:

c#

.net

Given the following hypothetical situation:

class ClassParent { }
interface IClassProvider { ClassParent Get(); }

Why is this then illegal IClassProvider implementation:

class ClassChild : ClassParent, IClassProvider
{
    ClassChild Get() { return this; }
}

It also doesn't work for inheriting properties and implementing base class instead of an interface like in the example.

ClassChild is ClassParent. Why does it not compile then? The compiler is clearly aware of a compile-time type of a class, that's why the following works:

void DoSomething(object o) { ... };
void DoSomething(ConcreteClass c) { ... };

DoSomething(new ConcreteClass()); //Calls the second overload of the method because of static type resolving

In layered scenarios this forces me to have a bunch of proxy-methods and needlessly clutter my code when the underlying situation is clear. Frankly I can't think of any problems or ambiguities if that was supported. I would be happy with compile-time (static) resolution, like it works with overloads in the second example.

Edit: I know that the compiler expects the following:

class ClassChild : ClassParent, IClassProvider
{
    ClassParent Get() { return this; }
}

and I know that it would work, I'm asking for an explanation why is it not supported or a scenario in which it would cause either a) problems or b)ambiguities worse than with overloads, which are supported.

Edit 2: This is as it seems another duplicate of a same old question as answered by apparently MS himself in this SO question. I'm marking @Euphoric 's post as answer because he provided a name for the feature which helped finding the "solution".

like image 356
Boris B. Avatar asked Dec 28 '22 01:12

Boris B.


2 Answers

I think feature you are looking for is name Covariant Return Type

As to "why" is it not implemented, noone knows. IMO this feature is not so needed, so it is simply not implemented.

And especialy in your case it can be easily solved using Explicit Interface Implementation

like image 90
Euphoric Avatar answered Jan 26 '23 00:01

Euphoric


While not exactly your question, you could implement something like this:

class ClassParent { }

    interface IClassProvider<T> where T: ClassParent
    {
        T Get();
    }

    class ClassChild : ClassParent,IClassProvider<ClassChild>
    {

        public ClassChild Get()
        {
            return this;
        }
    }

Or, to the more extreme (which gives you more type safety)

public class ClassParent { }

    interface IClassProvider<T> where T : ClassParent, IClassProvider<T>
    {
        T Get();
    }

    class ClassChild : ClassParent, IClassProvider<ClassChild>
    {

        public ClassChild Get()
        {
           return this;
        }
    }

EDIT:

the second version is a bit more type safe because this wont compile:

public class SomeOtherChildClass : ClassParent { }

class ClassChild : ClassParent, IClassProvider<SomeOtherChildClass>
    {

        public SomeOtherChildClass Get()
        {
           return this;
        }
    }

you could however write something like this, so it's not exactly perfect:

public class SomeOtherChildClass : ClassParent, IClassProvider<SomeOtherChildClass> { //implementation }

class ClassChild : ClassParent, IClassProvider<SomeOtherChildClass>
    {

        public SomeOtherChildClass Get()
        {
           return something;
        }
    }

I'm not sure if type safety is exactly the correct term. What I wanted to achieve is an object that can be provided only it implements a provider.

like image 29
Linkgoron Avatar answered Jan 26 '23 00:01

Linkgoron