C# new关键字和对象类型转换(双括号、is操作符、as操作符)

一、new关键字

CLR要求所有的对象都通过new来创建,代码如下:

Object obj=new Object();

以下是new操作符做的事情

1、计算类型及其所有基类型(一直到System.Object,虽然它没有定义自己的实例字段)中定义的所有实例字段需要的字节数.堆上每个对象都需要一些额外的成员,包括“类型对象指针”和"同步索引块"。CLR利用这些成员管理对象.额外成员的字节数要计入对象的大小.

2、从托管堆中分配类型要求的字节数,从而分配对象的内存,分配的所有字节都设为0

3、初始化对象的"类型对象指针"和"同步索引块"成员

4、调用类型的实例构造器,传递在new调用中指定的实参,大多数编译器都在构造器中自动生成代码来调用基类构造器,每个类型的构造器都负责初始化该类型定义的实例字段.最终调用System.Object的构造器,该构造器什么都不做.

注:没有和new操作符对应的delete操作符,换言之,没有办法显示释放为对象分配的内存.CLR采用了垃圾回收机制,能自动检测到一个对象不在被使用或者访问,并自动释放对象的内存.

二、对象类型转换

1、基础知识

CLR最重要的特性之一就是类型安全.在运行时,CLR总能知道当前对象是什么类型,调用GetType方法即可知道当前对象是什么类型,由于GetTpye是非虚方法,所以一个类型不能伪装成另一个类型.例如Employee类型不能重写GetType方法来返回一个SuperHero类型.

但是,日常开发中,经常需要将一种类型转换成另一种类型,CLR允许将对象转换成其实际类型或者它的任何基类型.每种编程语言都规定了开发人员具体如何进行这种转换.C#不要求任何特殊语法即可将对象转换成它的基类型,因为向基类型转换被认为是一种类型安全的转换.

对象转换成基类型的代码如下:

    public class Program
    {
        static void Main(string[] args)
        {
            //因为CLR中,Object是所有类型的基类,所以不需要转型
            Object obj = new Person();
        }
    }
    internal class Person { }

然而将一个对象转换成其派生类型(也就是子类型)时,C#要求进行显式的转换,因为这种转换可能会在运行时失败!

将对象转换成其派生类型(子类型),代码如下:

    public class Program
    {
        static void Main(string[] args)
        {
            //因为CLR中,Object是所有类型的基类,所以不需要转型
            Object obj = new Person();

            //需要强制转换,因为Person派生自Object
            Person p = (Person)obj;
        }
    }
    internal class Person { }

注:进行强制转换的对象必须是接收类型的派生类型,如果不是,编译器会报System.InvalidCastException异常.

2、使用is和as来进行强制转换

(1)、is操作符

C#中进行类型转换的另一种方式是使用is操作符,is检查对象是否兼容于指定类型,返回boolean值true或者false,注意:is操作符永远不抛出异常,代码如下:

    public class Program
    {
        static void Main(string[] args)
        {
            Object obj = new Object();
            Console.WriteLine(obj is Person);
            Person p = new Person();
            Console.WriteLine(p is Person);
            Console.ReadKey();
        }
    }
    internal class Person { }  

is操作符通常像下面这样使用:

if (stu is Person)
{
    Person p = (Person)stu;
}

在上述的代码中,CLR实际进行了两次的代码检查,is操作符首先核实stu是否兼容于Person类型,如果是,在if语句内部转型时,CLR再次核实stu是否引用一个Person类型,CLR的类型检查增强了安全性,但无疑会对性能造成一定的影响,应为CLR首先必须去判断变量引用的实际类型,用每个基类型去核对指定的类型.

2、as操作符

为了简化is操作符的做法,同时提供is操作符的性能,C#专门提供了as操作符,as操作符的工作方式与强制类型转换一样,只是它永远不抛出异常,如果对象不能转换,结果就是null.所以正确使用as操作符的做法是检查转型结果是否为null,如果直接使用这个结果可能会抛出System.NullReferenceException异常,代码如下:

    public class Program
    {
        static void Main(string[] args)
        {
            Object obj = new Object();
            Person p = obj as Person;//这个转换会失败,但是p会被设为null,不抛出异常
            string exceptionInfo = p.ToString();//这里访问p会抛出异常
            Console.WriteLine(exceptionInfo);
            Console.ReadKey();
        }
    }
    internal class Person { } 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏python学习指南

Python爬虫(十)_正则表达式

本篇将介绍python正则表达式,更多内容请参考:【python正则表达式】 什么是正则表达式 正则表达式,又称规则表达式,通常被用来检索、替换那些符合某...

2586
来自专栏编程

对Python中的类做简要的分析

在Python中,定义类是通过class关键字,class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪...

19410
来自专栏java达人

Java运行时多态性:继承和接口的实现

image.png Java是面向对象的语言,而运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Ja...

2575
来自专栏Python小屋

Python获取numpy数组中最大的5个元素(保持原顺序)

本文主要演示numpy的argsort()函数的用法。这个函数的返回值是数组中的元素排序后的原下标,例如np.argsort([3,1,2])的返回结果是arr...

3496
来自专栏小樱的经验随笔

【Java学习笔记之五】java数组详解

数组 概念 同一种类型数据的集合。其实数组就是一个容器。 数组的好处 可以自动给数组中的元素从0开始编号,方便操作这些元素...

2868
来自专栏Android开发指南

5:面向对象总结

36812
来自专栏塔奇克马敲代码

第 14 章 重载运算与类型转换

2276
来自专栏Google Dart

Dart 中构造函数定义与使用详解 原

在这种没有构造函数的情况下Dart会为其隐式定义一个默认构造函数(与类名相同、无参数)

1952
来自专栏游戏杂谈

C++学习笔记 -- 函数指针与指针函数

函数指针:指向函数的指针,首先它是指针变量(同指向一个整形变量、字符、数组一样),其次它指向一个函数(地址)。

2872
来自专栏java架构师

实例讲解override和new的区别

一、override:Override关键字主要是提供派生类对基类方法的新实现。 1、不可以用于重写非虚方法和静态方法 2、与其配套使用的关键字是Virtual...

34510

扫码关注云+社区

领取腾讯云代金券