开发者

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

开发者 https://www.devze.com 2023-02-11 21:33 出处:网络
Given the following hypothetical situation: class ClassParent { } interface IClassProvider { ClassParent Get(); }

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 i开发者_如何学JAVAs 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".


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


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.


IClassProvider's Get() method expects its implementers to return anything that inherits from, or is an instance of, ClassParent.

You're violating the contract stipulated by the interface by telling its implementer to only return objects of one specific subclass of ClassParent, which, due to the nature of single inheritance in classes, is why it isn't allowed.


Now it makes sense.

The signature must match exactly, like this

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


What's the problem with using explicit interface implementatin as Euphoric suggests?

class ClassChild : ClassParent, IClassProvider
{

   public ClassParent IClassProvider.Get()
   {
      return Get();
   }

   public ClassChild Get()
   {
      return this;
   }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消