[你必须知道的.NET] 第五回:深入浅出关键字---把new说透(转载)

[你必须知道的.NET] 第五回:深入浅出关键字---把new说透

 作者:Anytao

 

 本文将介绍以下内容:

  • 面向对象基本概念
  • new关键字深入浅出
  • 对象创建的内存管理 

1. 引言

园子里好像没有或者很少把new关键字拿出来说的,那我就占个先机吧,呵呵。那么,我们到底有必要将一个关键字拿出来长篇大论吗?看来是个问题。回答的关键是:你真的理解了new吗?如果是,那请不要浪费时间,如果不是,那请继续本文的循序之旅。

下面几个 问题可以大概的考察你对new的掌握,开篇之前,希望大家做个检验,如果通过了,直接关掉本页即可。如果没有通过,希望本文的阐述能帮你找出答案。

  1. new一个class对象和new一个struct或者enum有什么不同?
  2. new在.NET中有几个用途,除了创建对象实例,还能做什么?
  3. new运算符,可以重载吗?
  4. 范型中,new有什么作用?
  5. new一个继承下来的方法和override一个继承方法有何区别?
  6. int i和int i = new int()有什么不同?

2. 基本概念

一般说来,new关键字在.NET中用于以下几个场合,这是MSDN的典型解释:

  • 作为运算符, 用于创建对象和调用构造函数。

本文的重点内容,本文在下一节来重点考虑。

  • 作为修饰符,用于向基类成员隐藏继承成员。

作为修饰符,基本的规则可以总结为:实现派生类中隐藏方法,则基类方法必须定义为virtual;new作为修饰符,实现隐藏基类成员时,不可和override共存,原因是这两者语义相斥:new用于实现创建一个新成员,同时隐藏基类的同名成员;而override用于实现对基类成员的扩展。

另外,如果在子类中隐藏了基类的数据成员,那么对基类原数据成员的访问,可以通过base修饰符来完成。

例如: 

ContractedBlock.gifExpandedBlockStart.gifnew作为修饰符
using System;

namespace Anytao.net.My_Must_net
{
    class Number
    {
        public static int i = 123;

        public void ShowInfo()
        {
            Console.WriteLine("base class---");
        }

        public virtual void ShowNumber()
        {
            Console.WriteLine(i.ToString());
        }
    }

    class IntNumber : Number
    {
        new public static int i = 456;

        public new virtual void ShowInfo()
        {
            Console.WriteLine("Derived class---");
        }

        public override void ShowNumber()
        {
            Console.WriteLine("Base number is {0}", Number.i.ToString());
            Console.WriteLine("New number is {0}", i.ToString());            
        }
    }

    class Tester
    {
        public static void Main(string[] args)
        {
            Number num = new Number();
            num.ShowNumber();
            IntNumber intNum = new IntNumber();
            intNum.ShowNumber();

            Number number = new IntNumber();
            //究竟调用了谁?
            number.ShowInfo();
            //究竟调用了谁?
            number.ShowNumber();
        }
    }
}
  • 作为约束,用于在泛型声明中约束可能用作类型参数的参数的类型。

MSDN中的定义是:new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。当泛型类创建类型的新实例时,将此约束应用于类型参数。

注意:new作为约束和其他约束共存时,必须在最后指定。

其定义方式为:

class Genericer<T> where T : new()
    {
        public T GetItem()
        {
            return new T();
        }
    }

实现方式为:

class MyCls
    {
        private string _name;

        public MyCls()
        {
            _name = "Emma";
        }
    }


class MyGenericTester
    {
        public static void Main(string[] args)
        {
            Genericer<MyCls> MyGen = new Genericer<MyCls>();
            Console.WriteLine(MyGen.GetItem().Name);
        }
    }
  • 使用new实现多态。 这不是我熟悉的话题,详细的内容可以参见 《多态与 new [C#]》,这里有较详细的论述。

3. 深入浅出

作为修饰符和约束的情况,不是很难理解的话题,正如我们看到本文开篇提出的问题,也大多集中在new作为运算符的情况,因此我们研究的重点就是揭开new作为运算符的前世今生。

Jeffrey Richter在其著作中,极力推荐读者使用ILDASM工具查看IL语言细节,从而提高对.NET的深入探究,在我认为这真是一条不错的建议,也给了自己很多提高的空间挖掘。因此,以下是本人的一点建议,我将在后续的系列中,关于学习方法论的讨论中深入探讨,这里只是顺便小议,希望有益于大家。
1 不断的学习代码;
2 经常看看IL语言的运行细节,对于提供.NET的认识非常有效。

文归正题,new运算符用于返回一个引用,指向系统分配的托管堆的内存地址。因此,在此我们以Reflector工具,来了解以下new操作符执行的背后,隐藏着什么玄机。

首先我们实现一段最简单的代码,然后分析其元数据的实现细节,来探求new在创建对象时到做了什么? 

ContractedBlock.gifExpandedBlockStart.gifnew作为运算符
using System;

namespace Anytao.net.My_Must_net
{
    class MyClass
    {
        private int _id;

        public MyClass(int id)
        {
            _id = id;
        }
    }

    struct MyStruct
    {
        private string _name;

        public MyStruct(string name)
        {
            _name = name;
        }
    }

    class NewReflecting
    {
        public static void Main(string[] args)
        {
            int i;
            int j = new int();
            MyClass mClass = new MyClass(123);
            MyStruct mStruct = new MyStruct("My Struct");
        }
    }
}

使用Reflector工具反编译产生的IL代码如下为: 

ContractedBlock.gifExpandedBlockStart.gifIL元数据分析
.method public hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 num,
        [1] int32 num2,
        [2] class Anytao.net.My_Must_net._05_new.MyClass class2,
        [3] valuetype Anytao.net.My_Must_net._05_new.MyStruct struct2)
    L_0000: nop 
    
    //初始化j为0
    L_0001: ldc.i4.0 
    L_0002: stloc.1 
    
    //使用newobj指令创建新的对象,并调用构造函数以0x76(123的16进制)初始化
    L_0003: ldc.i4.s 0x7b    
    L_0005: newobj instance void Anytao.net.My_Must_net._05_new.MyClass::.ctor(int32)
    L_000a: stloc.2 
    //加载“My Struct”
    L_000b: ldloca.s struct2
    L_000d: ldstr "My Struct"
    //调用构造函数执行初始化
    L_0012: call instance void Anytao.net.My_Must_net._05_new.MyStruct::.ctor(string)
    L_0017: nop 
    L_0018: ret 
}

从而可以得出以下结论:

  • new一个class时,new完成了以下两个方面的内容:一是调用newobj命令来为实例在托管堆中分配内存;二是调用构造函数来实现对象初始化。
  • new一个struct时,new运算符用于调用其带构造函数,完成实例的初始化。
  • new一个int时,new运算符用于初始化其值为0。
  • 另外必须清楚,值类型和引用类型在分配内存时是不同的,值类型分配于线程的堆栈(stack)上,并变量本身就保存其实值,因此也不受GC的控制,;而引用类型变量,包含了指向托管堆的引用,内存分配于托管堆(managed heap)上,内存收集由GC完成。 

另外还有以下规则要多加注意:

  • new运算符不可重载。
  • new分配内存失败,将引发OutOfMemoryException异常。 

对于基本类型来说,使用new操作符来进行初始化的好处是,某些构造函数可以完成更优越的初始化操作,而避免了不高明的选择,例如:

string str = new string('*', 100);

string str = new string(new char[] {'a', 'b', 'c'});

而不是

string str = "***************************************"; 

4. 结论

    我能说的就这么多了,至于透了没透,作者的能量也就这么多了。希望园子的大牛们常来扔块砖头,对我也是一种莫大的促进。但是作为基本的原理和应用,我想对大部分的需求是满足了。希望这种力求深入浅出的介绍,能给你分享new关键字和其本质的来龙去脉能有所帮助。 

言归正传,开篇的几个题目,不知读者是否有了各自的答案,我们不妨畅所欲言,做更深入的讨论,以便揭开其真实的面纱。 

参考文献

(USA)Stanley B.Lippman, C# Primer

(USA)David Chappell Understanding .NET

Welcome to Anytao.com 

广而告之

[预告]

另外鉴于前几个主题的讨论中,不管是类型、关键字等都涉及到引用类型和值类型的话题,我将于近期发表相关内容的探讨,同时还有其他的关键字值得研究,这是本系列近期动向,给自己做个广告。祝各位愉快。 

[声明] 

本文的关键字new指的是C#中的关键字概念,并非一般意义上的.NET CRL范畴,之所以将这个主题加入本系列,是基于在.NET体系下开发的我们,何言能逃得过基本语言的只是要点。所以大可不必追究什么是.NET,什么是C#的话题,希望大家理清概念,有的放肆。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/549819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ap测试系统软件,符合AUTOSAR(APCP)的嵌入式系统和软件设计工具

AUTOSAR Builder功能介绍AUTOSAR Builder 是达索旗下一款基于 Eclipse 的开放、可扩展工具套件&#xff0c;用于设计和开发符合 AUTOSAR 标准的系统和软件。新版本2020x支持AUTOSAR Classic 4.4.0及AUTOSAR Adaptive R19-03。图1 AUTOSAR Builder工具主界面AUTOSAR Authoring …

开发手记之实现web.config的快速配置(转载)

开发手记之实现web.config的快速配置 开发手记之实现web.config的快速配置 作者&#xff1a;Anytao 问题简述&#xff1a; 在Web开发中&#xff0c;对web.cofig进行配置是非技术人员无法胜任的工作&#xff0c;但是常常需要由客户自己来进行简单配置的时候&#xff0c;需要提…

ASP.NET 2.0中实现模板中的数据绑定

模板化的数据绑定控件为我们在页面上显示数据提供了根本的灵活性。你可能还记得ASP.NET v1.x中的几个模板化控件&#xff08;例如DataList和Repeater控件&#xff09;。ASP.NET 2.0仍然支持这些控件&#xff0c;但在模板中绑定数据的语法已经被简化和改善了。本文将讨论在数据绑…

现实世界的虚拟神话

本文摘自&#xff1a;[url]http://www.doserv.com/news/f/2007-03-12/0017031936.shtml[/url]如今&#xff0c;服务器虚拟化已经成为业界的最为热门的话题之一。虚拟化技术自问世以来&#xff0c;人们纷纷为其神奇的效果而赞不绝口。正如VMware创始人兼CEO Diane Greene所说&am…

GridView中妙用LinkButton

说明&#xff1a;近来看到不少人想在DataGrid、GridView 使用比较灵活的方式来编辑、查看、删除其中的数据选项&#xff08;当然它们本身也内置了这些功能&#xff09;&#xff0c;却苦于找不到比较好的办法&#xff0c;本人结合实际代码说明一下如何使用LinkButton来实现上述功…

计算机ppt文字1是什么原因,ppt让答案一个个出现,ppt让文字一个个出现

在使用Windows 10工作时会遇到形形色色的问题&#xff0c;比如开机发现无法连接网络。那么如何进行故障排除呢&#xff1f;下面小编与你分享具体步骤和方法。工具/材料Windows 10操作系统操作方法01启动Windows 10操作系统&#xff0c;如图所示。点击任务栏搜索框&#xff0c;开…

抢先试用ReSharper UnitRun™ 1.0

在发布又一款免费的VS2005单元测试插件后随即安装了个ReSharper UnitRun™ 1.0玩玩&#xff0c;发现的确有其亮点&#xff0c;尤其喜欢的是在执行单元测试的过程中居然支持调试。 在安装过程中遇到个问题&#xff0c;一个注册的异常&#xff0c;后来到其官网上注册并得到个lice…

python day27

今日内容 知识点补充 import jsonfrom datetime import datetime,date""" res {c1:datetime.today(),c2:date.today()} print(json.dumps(res)) 返回结果:TypeError: Object of type datetime is not JSON serializable """ class MyJson(json.…

硬件_LED

LED 平台&#xff1a;全志A64 源码&#xff1a;Android 7.1 Linux 3.1 led.c 1 //没有使用平台总线2 3 #include <linux/init.h>4 #include <linux/module.h>5 #include <linux/fs.h>6 #include <linux/device.h>7 #include <linux/slab.h>8 #i…

水星路由器DNS服务器未响应,水星路由器进不去设置怎么办

摘 要水星路由器进不去设置怎么办&#xff1f;这里要分两种情况&#xff0c;旧版水星路由器与新版水星路由器一、旧版水星路由器 1、当打开水星路由器设置页面&#xff0c;如果提示你输入用户名和密码&#xff0c;如下图所示。说明这是一台旧版本的水星路由器水星路由器进不去设…

zookeeper 简介

什么是ZookeeperZookeeper是一个分布式开源框架&#xff0c;提供了协调分布式应用的基本服务&#xff0c;它向外部应用暴露一组通用服务——分布式同步&#xff08;Distributed Synchronization&#xff09;、命名服务&#xff08;Naming Service&#xff09;、集群维护&#x…

小程序的服务器怎么与数据库连接,小程序怎么连接服务器数据库

小程序怎么连接服务器数据库 内容精选换一换“数据导出”章节适用于MRS 3.x及后续版本。Loader是实现MRS与关系型数据库、文件系统之间交换数据和文件的ETL工具&#xff0c;支持将数据或者文件从MRS系统中导出到关系型数据库或文件系统中。Loader支持如下数据导出方式&#xff…

啪啪三国2获取服务器信息,啪啪三国2怎么快速的获得资源?

啪啪三国2&#xff1a;在啪啪三国2手游中有很多特色的玩法&#xff0c;还有很多资源&#xff0c;游戏中有很多地方需要用到&#xff0c;有点供不应求的感觉&#xff0c;很多玩加都想要快速的获得各种资源。小伙伴们知道该怎么快速获得吗&#xff1f;这里小编就给大家来详细的介…

C#常用的文件操作 (转)

C#常用的文件操作 C#常用的文件操作&#xff08;网上收集&#xff09; C#写入/读出文本文件&#xff0c;包括创建文件&#xff0c;追加文件&#xff0c;修改文件&#xff0c;等等操作&#xff0c;个人觉得很适用&#xff0c;所以收藏了&#xff0c;和大家分享 publicvoidPage…

CSS3动画和VUE动画整理

W3School CSS3过渡 浏览器支持 Internet Explorer 10、Firefox、Chrome 以及 Opera 支持 transition 属性。Safari 需要前缀 -webkit-。 注释&#xff1a;Internet Explorer 9 以及更早的版本&#xff0c;不支持 transition 属性。 注释&#xff1a;Chrome 25 以及更早的版本…

VueJS项目

VueJS项目 - awesome-vue vue-cli引用jquery, bootstrap, bootstrap-table 引用jquery 找到vue-project/build/webpack.base.conf.js文件&#xff0c;在module.exports下添加plugins, 需要在之前&#xff0c;引用webpack, var webpack require(webpack); 参考 plugins: [n…

[OSG]如何用Shader得到物体的世界坐标

最近群里面有个朋友问我关于如何得到OpenGL世界坐标的问题&#xff0c;当时我还弄错了&#xff0c;误以为gl_ModelViewMatrix*gl_Vertex就是世界坐标。因最近也突然遇到了世界坐标的问题&#xff0c;所以花了一些时间来研究这个问题&#xff0c;网上也有人问&#xff0c;但或许…

Exposing Windows Forms Controls as ActiveX controls

转&#xff1a;http://www.codeproject.com/cs/miscctrl/exposingdotnetcontrols.asp?df100&forumid2373&exp0&select1359005 Download demo project - 15 Kb This article will describe how to utilise Windows Forms controls outside of .NET. In a recent MS…

QT_C++

QT_C C 与 C 区别&#xff1a;  面向过程&#xff1a;吃&#xff08;狗&#xff0c;屎&#xff09; 面向对象&#xff1a;狗. 吃&#xff08;屎&#xff09; ^ . ^ 博客&#xff1a;https://www.runoob.com/cplusplus/cpp-tutorial.html 插入符&#xff1a;<< 控制符…

静态路由的实现

在路由器A上做如下配置&#xff1a;router(config)#hostname AA(config)#interface f0/0A(config-if)#ip address 192.168.1.1 255.255.255.0 A(config-if)#no shutdownA(config)#interface f0/1A(config-if)#ip address 192.168.2.1 255.255.255.0 A(config-if)#no shutdownA(…