C#类类型转换

本文关键字:类型转换 | 更新日期: 2023-09-27 18:21:59

这是一个很难在网上解释的问题,但我会尽力的。我实例化了一个B类型的对象,它存储在a类型的变量中。我使用get type属性,所以现在它是B类型。因此,我是否执行了a和B类型的隐式转换。因此,当调用.show()时,它是B型的吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    class A
    {
        public virtual void show()
        {
            Console.WriteLine("Showing A");
        }
        public void test()
        {
            Console.WriteLine("called from A");
        }
    }
    class B:A
    {
        public override void show()
        {
            Console.WriteLine("Showing B");
        }
        public void testb()
        {
            Console.WriteLine("called from B");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {

            A a = new B();
            // Outputs ConsoleApplication.B
            Console.WriteLine("{0}", a.GetType());
            // outputs showing B
            a.show();
            // outputs called from A
            a.test();
            Console.ReadLine();
        }
    }
}

C#类类型转换

您没有执行隐式转换,因为您实际上没有转换任何内容。

A a = new B();

您已经直接实例化了一个类型为B的对象。您可以从类型为a的变量中引用它,因为B是a的子类。但是,这两个操作应该被视为独立的。

…=new B();

将始终实例化类型为B的对象,而不管左边是什么。

A a = ...

将始终尝试将右边的内容分配给变量a.

引用类型的唯一区别在于CLR如何查看对象。

A a = new B();
B b = new B();

两者都是B类型的对象。然而,"a"只允许您将其视为a类型的对象来处理。因此,您只能调用a.show()和a.test(),即使它实际上是B类型,因此有额外的方法testb()b'将允许您调用b.show()、b.test()和b.testb()。无论变量类型如何,当您调用show()时,它都是b类型的,因此返回的是overriden show()方法。

最后,你现在能做的是沮丧。即,您实例化了一个类型为B的对象,因此现在可以将其强制转换为类型为B的变量,从而允许对所有类型为B成员进行完全访问。

例如:

A a = new B();
a.testb(); // this will not compile as a does not have a definition of testb().
A a = new B();
B b = (B)a; // downcast a to a reference of type B
b.testb(); // this is now fine

我刚刚看到你的另一个问题,你为什么要把一些东西实例化为类型A,即基类。这是为了提供一个共同点,作为处理不同类型对象的一种方式。例如,你可能有一个基本类型的动物,并从中衍生出几个子类——猫、狗、沙鼠。但是,您可能希望能够将所有动物的列表传递给只需要使用公共属性的方法。因此,如果Animal有一个名字,你的列表可以重复,并引用每个Animals的名字,即使Animal本身可能是抽象的(无法命名),并且列表完全由狗、猫和沙鼠组成。然后,你也可以通过找出与各种动物进一步互动的类型来向下分析它们,例如

if (animal is Dog) {
    Dog dog = (Dog)animal;
}

或者您可以使用关键字"as"来执行强制转换:

Dog dog = animal as Dog;

希望这能有所帮助。

因为您将其存储在类型a的变量中,所以您的变量仍然引用类型B的对象。当您对变量"a"进行调用时,CLR知道要调用的正确方法。由于您重写了show方法,因此将调用类型为B的show方法。但是您没有重写test(),所以调用了类型A上的方法实现。这是可能的,因为B从A"继承"了test()行为,但没有覆盖它。

在您的代码中:

 // outputs showing B
  a.show();

打印"显示B",因为show()是一个虚拟方法。任何虚拟方法调用都是由对象类型决定的,而不是引用的类型(后期绑定)。引用CCD_ 2指向类型为B的对象。

  // outputs called from A
  a.test();

test()只是从类A继承而来,而不是一个虚拟方法,因此它打印"从a调用"。方法调用a.GetType()不转换任何内容,它只是返回一个Type对象的实例。

变量a指向类型为B的实例,因此不需要将a.show()转换为B.show()方法。这正是虚拟方法应该做的:调用变量引用的实例化类型(或继承链中的第一个实现)上的方法,而不是变量的声明类型。

a.test()的调用不会执行此操作,因为该方法未声明为virtual。所以它只是简单地调用A.test()方法。

如其他文章中所述,您已经创建了一个类型B的实例,但由于您将对象向上转换为类型A,因此为类型A定义了接口。

如果需要访问为类型B定义的方法,可以将对象向下转换为它的原始类型,从而为类型B提供定义。

例如:

if (a is B)
{
    ((B)a).testb();
}
// or
B b = a as B;
if (b != null)
{
    b.testb();
}