C#:为什么安全强制转换(as)返回重写的方法而不是基方法?

C#:为什么安全强制转换(as)返回重写的方法而不是基方法?,c#,casting,C#,Casting,查看as关键字在C#中的工作方式,我可以看到它允许在显式转换(即使用括号)阻止编译的情况下进行转换 但是,在下面的代码中,我发现如果我重写派生类中的方法,然后将其安全转换为基类,那么派生类中被重写的方法仍然会执行。为什么会这样?我希望基类上定义的方法能够执行 class Base { public override string ToString() { return base.ToString(); } public string OtherM

查看
as
关键字在C#中的工作方式,我可以看到它允许在显式转换(即使用括号)阻止编译的情况下进行转换

但是,在下面的代码中,我发现如果我重写派生类中的方法,然后将其安全转换为基类,那么派生类中被重写的方法仍然会执行。为什么会这样?我希望基类上定义的方法能够执行

class Base
{
    public override string ToString()
    {
        return base.ToString();
    }

    public string OtherMethod()
    {
        return "Other method";
    }
}

class Derived : Base
{
    public override string ToString()
    {
        return "Derived class";
    }
}

class Program
{
    static void Main()
    {
        Derived d = new Derived();
        Base b = new Base();

        System.Console.WriteLine(b.ToString()); // Base
        System.Console.WriteLine(d.ToString()); // Derived class
        System.Console.WriteLine((d as Base).ToString()); // Derived class => WHY IS THIS?
        System.Console.WriteLine((d as Base).OtherMethod()); // Other method
        // System.Console.WriteLine((Base)d.OtherMethod()); // --- prevents compilation

        // As noted in the comments, this works
        System.Console.WriteLine(((Base)d).OtherMethod()); // Other method

        System.Console.ReadLine();
    }
}

这就是继承和多态性在C#中的工作原理。
as
操作符只执行安全强制转换,但在内部它仍然是一个
派生的
。它只是更改它,以便编译器知道它具有正确的类型。对于你的类型,铸造是不必要的。这只会起作用:

 Base d = new Derived();
这仍将调用由
Derived
覆盖的虚拟方法

至于显式强制转换,它失败了,因为它的优先级低于该表达式上的其他运算符。首先评估整个右手侧,然后评估石膏。本质上,这就是您要告诉编译器的内容

 string result = d.OtherMethod();
 Base result2 = (Base)d;

这就是继承和多态性在C#中的工作原理。
as
操作符只执行安全强制转换,但在内部它仍然是一个
派生的
。它只是更改它,以便编译器知道它具有正确的类型。对于你的类型,铸造是不必要的。这只会起作用:

 Base d = new Derived();
这仍将调用由
Derived
覆盖的虚拟方法

至于显式强制转换,它失败了,因为它的优先级低于该表达式上的其他运算符。首先评估整个右手侧,然后评估石膏。本质上,这就是您要告诉编译器的内容

 string result = d.OtherMethod();
 Base result2 = (Base)d;
这有望有助于:

基类可以定义和实现虚拟方法,派生类可以覆盖它们,这意味着它们提供自己的定义和实现在运行时,当客户端代码调用该方法时,CLR会查找对象的运行时类型,并调用虚拟方法的覆盖。因此,在源代码中,可以对基类调用方法,并执行派生类版本的方法

在您的例子中,您正在调用
对象.ToString()
虚拟方法,并且在运行时选择了适当的覆盖。

这可能会有帮助:

基类可以定义和实现虚拟方法,派生类可以覆盖它们,这意味着它们提供自己的定义和实现在运行时,当客户端代码调用该方法时,CLR会查找对象的运行时类型,并调用虚拟方法的覆盖。因此,在源代码中,可以对基类调用方法,并执行派生类版本的方法


在您的情况下,您正在调用
对象.ToString()
虚拟方法,并且在运行时选择了适当的覆盖。

只有在出现阴影的情况下,才需要对基类进行强制转换并导致执行不同的方法

当派生类实现了与基类1中的方法同名的方法,并且明确地说,这不是一个
重写时,就会发生阴影。通常,它们会用关键字
new
进行标记。如果您有一个派生类的实例,但希望调用基类成员,则需要将其强制转换到该基类(或者转换到继承链中本身不影响所讨论方法的任何中间类)

在没有阴影的情况下,任何方法调用都始终使用最派生的方法,基于对象的运行时类型,而不是变量的声明类型

然而,阴影通常是最好避免的



1不一定是直接基类-继承链中回到
对象的任何位置

唯一需要对基类进行强制转换并导致执行不同方法的时间是在出现阴影的情况下

当派生类实现了与基类1中的方法同名的方法,并且明确地说,这不是一个
重写时,就会发生阴影。通常,它们会用关键字
new
进行标记。如果您有一个派生类的实例,但希望调用基类成员,则需要将其强制转换到该基类(或者转换到继承链中本身不影响所讨论方法的任何中间类)

在没有阴影的情况下,任何方法调用都始终使用最派生的方法,基于对象的运行时类型,而不是变量的声明类型

然而,阴影通常是最好避免的



1不一定是直接基类-继承链中返回到
对象的任何位置

标记为“阻止编译”的行不会因为类型转换而失败。它失败是因为您试图从
OtherMethod
强制转换返回值<代码>((Base)d).OtherMethod()
应该可以编译。您试图打破面向对象编程的多态性特性。幸运的是,您不能这样做,这将是不好的。它调用被重写的方法,因为该方法已被重写。这就是重写方法的全部要点,因此它们将被调用,而不是基方法。“这是为什么?”as操作符不会更改内存中对象的实际类型。它只返回对此对象的引用(如果强制转换失败,则返回null引用)。标记为“阻止编译”的行不会因为强制转换的类型而失败。它失败是因为您试图从
OtherMethod
强制转换返回值<代码>((Base)d).OtherMethod()
应该可以编译。您试图打破面向对象编程的多态性特性。L