C# 重写方法以更改返回类型

C# 重写方法以更改返回类型,c#,C#,在这种情况下,我希望重写基类的一个方法,以便稍微更改该方法的返回类型。我所说的轻微更改是指返回一个从基类型中的方法返回的对象继承的对象。。。实际上,一点代码会让这更容易 class Program { static void Main(string[] args) { var obj = new ParentClass(); Console.WriteLine("Parent says: " + obj.ShowYourHand());

在这种情况下,我希望重写基类的一个方法,以便稍微更改该方法的返回类型。我所说的轻微更改是指返回一个从基类型中的方法返回的对象继承的对象。。。实际上,一点代码会让这更容易

class Program
{
    static void Main(string[] args)
    {
        var obj = new ParentClass();
        Console.WriteLine("Parent says: " + obj.ShowYourHand());

        var obj2 = new ChildClass();
        Console.WriteLine("Child says: " + obj2.ShowYourHand());

        Console.ReadLine();
    }
}

public class ParentClass
{
    public string ShowYourHand()
    {
        var obj = GetExternalObject();
        return obj.ToString();
    }
    protected virtual ExternalObject GetExternalObject()
    {
        return new ExternalObject();
    }
}

public class ChildClass : ParentClass
{
    protected virtual new ExternalObjectStub GetExternalObject()
    {
        return new ExternalObjectStub();
    }
}

public class ExternalObject
{
    public override string ToString()
    {
        return "ExternalObject";
    }
}

public class ExternalObjectStub : ExternalObject
{
    public override string ToString()
    {
        return "ExternalObjectStub";
    }
}
我遇到的问题是,obj2的实例不调用它的GetExternalObject()版本,而是使用它的父级实现

我认为这样做是因为在代码中

var obj = GetExternalObject();
obj的类型应为父类中的ExternalObject。然而,我理解C#无法区分基于返回类型的方法

我知道这个问题还有其他解决方案,比如定义一个IExternalObject,所以不要太在意这个问题。我想知道的是,是什么想法阻止了子类GetExternalObject被调用,即使是子类本身

还是我在做一些完全愚蠢的事?:-)

还是我在做一些完全愚蠢的事?:-)

是的,你是。不能通过重写方法来更改其返回类型。无论如何,在你的样品中我不明白。只需保持返回类型不变,并返回一个新的
ExternalObjectStub
。这是可行的,因为
ExternalObjectStub
派生自
ExternalObject


通过在执行时使用
new
隐藏基成员来更改返回类型通常是一个非常糟糕的主意,因为它会导致无法以多态方式使用的类。这正是您在这里遇到的情况:如果保存引用的变量类型为
父类
,则它调用
父类
中的方法,即使实例的类型确实为
子类
,因为
ChildClass
在使用时没有提供
GetExternalObject

多态性的重写实现,这是不正确的。您需要在子类中创建一个新方法,该方法使用新的返回类型隐藏基类的实现。您不能像现在这样使用虚拟方法来重载方法

虚拟方法用于在子类中创建不同的方法实现,而不是像您试图做的那样“重载”

方法重载是通过更改参数而不是返回类型来完成的


因此,要么在子类中隐藏父方法,要么用另一个名称创建一个方法。使用virtual将不起作用。

如果要在子类中返回ExternalObjectStub,则此ExternalObjectStub应派生自ExternalObject类您应该让类返回一个接口,每个类(
ParentClass
ChildClass
)都返回接口的实例。您还应该重写
ChildClass
中的
GetExternalObject
方法,以便v-table指向正确的实现

另外,您的代码有一个输入错误——您的
Main
方法在调用
ShowYourHand
时引用了
obj
两次。我也将其更改为引用
obj
obj2
。下面是如何通过一个接口实现这一点(并修复Main中的
obj
typo):


我一点也不认为你在做傻事。我发现自己经常在寻找实现相同模式的方法(类Foo有一个Bar类型的属性,类FooSub:Foo应该能够将该属性公开为BarSub:Bar类型)

关于“new”操作符需要了解的一件重要事情是,它只隐藏子类本身的实现。如果子类被转换回基类,则使用基类的实现。因此,您需要确保有一个“real”方法要重写,以便即使发生这种情况,它仍然返回正确的类型

public class ParentClass
{
    public string ShowYourHand()
    {
        var obj = GetExternalObject();
        return obj.ToString();
    }

    protected ExternalObject GetExternalObject()
    {
        return this.RealGetExternalObject();
    }

    protected virtual ExternalObject RealGetExternalObject()
    {
        return new ExternalObject();
    }
}

public class ChildClass : ParentClass
{
    new protected ExternalObjectStub GetExternalObject()
    {
        return (ExternalObjectStub)this.RealGetExternalObject();
    }

    protected override ExternalObject RealGetExternalObject()
    {
        return new ExternalObjectStub();
    }
}
类似的问题:可能重复
public class ParentClass
{
    public string ShowYourHand()
    {
        var obj = GetExternalObject();
        return obj.ToString();
    }

    protected ExternalObject GetExternalObject()
    {
        return this.RealGetExternalObject();
    }

    protected virtual ExternalObject RealGetExternalObject()
    {
        return new ExternalObject();
    }
}

public class ChildClass : ParentClass
{
    new protected ExternalObjectStub GetExternalObject()
    {
        return (ExternalObjectStub)this.RealGetExternalObject();
    }

    protected override ExternalObject RealGetExternalObject()
    {
        return new ExternalObjectStub();
    }
}