C# 转换(引用转换)

发布于:2025-07-19 ⋅ 阅读:(10) ⋅ 点赞:(0)

引用转换

我们已经知道引用类型对象由内存中的两部分组成:引用和数据。

  • 由引用保存的那部分信息是它指向的数据类型。

  • 引用转换接受源引用并返回一个指向堆中同一位置的引用,但是把引用“标记”为其他
    类型。
    例如,如下代码给出了两个引用变量:myVar1和myVar2,它们指向内存中的相同对象。代
    码如图17-17所示。

  • 对于myvarl,它引用的对象看上去是3类型的对象一一一其实就是。

  • 对于myVar2,同样的对象看上去像A类型的对象。

    • 即使它实际指向B类型的对象,它也看不到B扩展A的部分,因此看不到Field2。
    • 第二个WriteLine语句因此会产生编译错误。
      注意,“转换"不会改变myVar1。
class A {public int Field1;}

class B:A {public int Field2;}

class Program
{
    static void Main()
    {
        B myVar1=new B();

        //作为A类的引用返回myVar1的引用
        A myVar2=(A)myVar1;

        Console.WriteLine($"{myVar2.Field1}"); //正确
        COnsole.WriteLine($"{mVar2.Field2}"); // 编译错误 Field2对于myVar2不可见
    }
}

引用转换返回与对象关联的不同类型

隐式引用转换

与语言为我们自动实现的隐式数字转换类似,还有隐式引用转换,如图17-18所示。

  • 所有引用类型可以被隐式转换为object类型。
  • 任何接口可以隐式转换为它继承的接口。
  • 类可以隐式转换为:
    • 它继承链中的任何类;
    • 它实现的任何接口。

类和接口的隐式转换

委托可以隐式转换成图17-19所示的.NETBCL类和接口。Arrays数组(其中的元素是Ts类
型)可以隐式转换成:

  • 图17-19所示的.NET BCL类和接口;
  • 另一个数组ArrayT,其中的元素是Tt类型(如果满足下面的所有条件)。
    • 两个数组维度的一样。
    • 元素类型Ts和Tt都是引用类型,不是值类型。
    • 在类型Ts和Tt中存在隐式转换。

委托和数组的隐式转换

显式引用转换

显式引用转换是从一个普通类型到一个更精确类型的引用转换。

  • 显式转换包括:
    • 从object到任何引用类型的转换;
    • 从基类到派生自它的类的转换。
  • 倒转图17-18和图17-19的箭头方向,可以演示显式引用转换。
    如果转换的类型不受限制,我们很容易尝试引用在内存中实际并不存在的类成员。然而,编
    译器确实允许这样的转换。但如果系统在运行时遇到它们,则会抛出异常。

例如,图17-20中的代码将基类A的引用转换到它的派生类B,并且把它赋值给变量myVar2。

  • 如果myVar2尝试访问Field2,它会尝试访问对象中"B部分"的字段(它不在内存中),
    这会导致内存错误。
  • 运行时会捕获到这种不正确的强制转换并且抛出InvalidCastException异常。然而,注
    意,它不会导致编译错误。

|无效的转换抛出运行时异常

有效显式引用转换

在运行时能成功进行(也就是不抛出InvalidCastException异常)的显式转换有3种情况。
第一种情况:显式转换是没有必要的。也就是说,语言已经为我们进行了隐式转换。例如,
在下面的代码中,显式转换是没有必要的,因为从派生类到基类的转换总是隐式转换。

class A {public int Field1;}
class B:A{public int Field2;}
...
B myVar1=new B();
A myVar2=(A)myVar2;  //不必转换,因为A是B的基类

第二种情况:源引用是null。例如,在下面的代码中,即使转换基类的引用到派生类的引用
通常是不安全的,但是由于源引用是null,这种转换还是允许的。

class A {public int Field1;}
class B:A{public int Field2;}
...
A myVar1=null;
B myVar2=(B)myVar1;  //允许转换,因为myVar1为空

第三种情况:由源引用指向的实际数据可以安全地进行隐式转换。如下代码给出了一个示例,
图17-21演示了这段代码。

  • 第二行中的隐式转换使myVar2看上去像指向A类型的数据,其实它指向的是B类型的数
    据对象。
  • 第三行中的显式转换把基类引用强制转换为它的派生类的引用。这通会产生异常。然
    而,在这种情况下,指向的对象实际就是B类型的数据项。
class A {public int Field1;}
class B:A{public int Field2;}

...
B myVar1=new B();
A myVar2=myVar1;     //将myVar1隐式转换为A类型
B myVar2=(B)myVar2;  //该转换是允许的,因为数据是B类型

强制转换到安全类型


网站公告

今日签到

点亮在社区的每一天
去签到