当前位置: 首页 > 编程日记 > 正文

【C#小知识】C#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...

目录:

【C#小知识】C#中一些易混淆概念总结

【C#小知识】C#中一些易混淆概念总结(二)

---------------------------------------分割线----------------------------------------------

一,C#中结构

在C#中可以使用struct关键字来定义一个结构,级别与类是一致的,写在命名空间下面。

1)结构中可以定义属性,字段,方法和构造函数。示例代码如下:

//定义结构struct Point{//定义字段private int x;//封装字段public int X{get { return x; }set { x = value; }}//定义方法public void Result(){}//定义构造函数public Point(int n){this.x = n;//Console.WriteLine(n);
        }}

那么,声明类与结构的区别有哪些呢?

无论如何,C#编译器都会为结构生成无参数的构造函数;

当我们显式的定义无参数的构造函数,编译时会报错,结果如下:

编译器告诉我们,结构不能包含显式的无参数的构造函数

但是这样编写代码时,编译器却不报错,代码如下:

 //这里可以调用无参数的构造函数Point p = new Point();Console.WriteLine(p.GetType());

运行结果如下:

 

虽然结构不能显式的声明无参数的构造函数,但是程序员却可以显式的调用结构的无参数的构造函数,说明C#编译器无论如何都会为结构生成无参数的构造函数。

 

②结构中的字段不能赋初始值;

 

 

③在结构的构造函数中必须要对结构体的每一个字段赋值;

当我们不声明显式的构造函数时,可以不对成员字段赋值,但是一旦声明了构造函数,就要对所有的成员字段赋值

对所有的成员字段赋值,代码如下:

     //定义构造函数public Point(int n){this.x = n;//Console.WriteLine(n);}

 

④在构造函数中对属性赋值不认为对字段赋值,属性不一定去操作字段;

 

所以在构造函数中我们对字段赋初始值的时候,正确的代码应该是

         //定义构造函数public Point(int n){//正确的可以对字段赋初始值this.x = n;//在构造函数中对属性赋值,但是不一定操作字段this.X = n;//Console.WriteLine(n);} 

2)结构体的数值类型问题

C#中的结构是值类型,它的对象和成员字段是分配在栈中的,如下图:

那么当我们写了如下的代码,内存中发生了什么呢?

         //这里可以调用无参数的构造函数Point p = new Point();//为p的属性赋值p.X = 100;//将p赋值给Point新的对象p1Point p1 = p;

Point p1=p发生了什么呢?情况如下:

 

声明结构体对象可以不使用“new”关键字如果不使用“new”关键字声明结构体对象,因为没有调用构造函数,这个时候结构体对象是没有值的。而结构的构造函数必须为结构的所有字段赋值,所以通过"new"关键字创建结构体对象的时候,这个对象被构造函数初始化就有默认的初始值了。实例代码如下

class Program{static void Main(string[] args){//没有办法调用默认的构造函初始化
            Point p;Console.WriteLine(p);//会调用默认的构造函数对的Point对象初始化Point p1 = new Point();Console.WriteLine(p1);Console.ReadKey();}}//定义结构struct Point{//定义时赋初始值,编译器会报错private int x;}

编译的时候会报错:

3)结构体不能使用自动属性

在第一篇文章我写自动属性的时候,反编译源代码,知道自动属性,会生成一个默认字段。而在结构的构造函数中需要对每一个字段赋值,但是编译器不知道这个字段的名字。所以,没有办法使用自动属性。

那么什么时候定义类,什么时候定义结构体呢?

首先我们都知道的是,栈的访问速度相对于堆是比较快的。但是栈的空间相对于堆来说是比较小的。

①当我们要表示一个轻量级的对象,就可以定义结构体,提高访问速度。

②根据传值的影响来选择,当要传递的引用就定义类,当要传递的是“拷贝”就定义结构体。

 

二,关于GC(.NET的垃圾回收)

1)分配在栈中的空间变量,一旦出了该变量的作用域就会被CLR立即回收;如下代码:

        //定义值类型的n当,程序出了main函数后n在栈中占用的空间就会被CLR立即回收static void Main(string[] args){int n = 5;Console.WriteLine(n);}

2)分配在堆里面的对象,当没有任何变量的引用时,这个对象就会被标记为垃圾对象,等待垃圾回收器的回收;

GC会定时清理堆空间中的垃圾对象,这个时间频率是程序员无法控制的,是由CLR决定的。所以,当一个对象被标记为垃圾对象的时候,不一定会被立即回收。

3)析构函数

在回收垃圾对象的时候,析构函数被GC自动调用。主要是执行一些清理善后工作。

析构函数没有访问修饰符,不能有你参数,使用“~”来修饰。 如下面的代码示例:

class Program{//定义值类型的n当,程序出了main函数后n在栈中占用的空间就会被CLR立即回收static void Main(string[] args){int n = 5;OperateFile operate = new OperateFile();operate.FileWrite();//执行完写操作后,会调用该类的析构函数,释放对文件对象的控制//Console.WriteLine(n);
        }}//定义操作硬盘上文件上的类class OperateFile{//定义写文件的方法public void FileWrite(){ }//定义调用该类结束后,所要执行的动作~OperateFile(){//释放对操作文件对象的控制}}

 三,静态成员和实例成员的区别:

静态成员是需要通过static关键字来修饰的,而实例成员不用static关键字修饰。他们区别如下代码:

 

class Program{static void Main(string[] args){//静态成员属于类,可以直接通过“类名.静态成员”的方式访问
            Person.Run();//实例成员属于对象,需要通过“对象名.实例成员”来访问Person p = new Person();p.Sing();}}class Person{//静态成员变量private static int nAge;//实例成员变量private string strName;public static void Run(){Console.WriteLine("我会奔跑!");}public void Sing(){Console.WriteLine("我会唱歌");}}

当类第一次被加载的时候(就是该类第一次被加载到内存当中),该类下面的所有静态的成员都会被加载。实例成员有多少对象,就会创建多少对象。

而静态成员只被加载到静态存储区,只被创建一次,且直到程序退出时才会被释放。

看下面的代码:

class Program{static void Main(string[] args){Person p = new Person();Person p1 = new Person();Person p2 = new Person();}}class Person{//静态成员变量private static int nAge;//实例成员变量private string strName;public static void Run(){Console.WriteLine("我会奔跑!");}public void Sing(){Console.WriteLine("我会唱歌");}}

那么在内存中发生了什么呢?如下图:

由上面显然可知,定义静态的成员是可以影响程序的执行效率的。那么什么时候定义静态的成员变量呢?

①变量需要被共享的时候②方法需要被反复的调用的时候 

 

2)在静态方法中不能直接调用实例成员。

 当类第一次被加载的时候,静态成员已经被加载到静态存储区,此时类的对象还有可能能没有创建,所以静态方法中不能调用类成员字段。实例代码如下:

this和base关键字都不能在静态方法中使用。

②可以创建类的对象指明对象的成员在静态方法中操作,代码如下:

 public static void Run(){Person p = new Person();p.strName = "强子";Console.WriteLine("我会奔跑!");}

③在实例成员中肯定可以调用静态方法,因为这个时候静态成员肯定存在,代码如下:

 public static void Run(){Person p = new Person();p.strName = "强子";Console.WriteLine("我会奔跑!");}public void Sing(){//实例方法被调用的时候,对象实例一定会被创建,所以可以在实例方法中访问实例的字段this.strName = "子强";strName = "子强";//调用静态成员
            Run();Console.WriteLine("我会唱歌");}

静态成员和实例成员的对比:

①生命周期不一样

静态成员只有在程序结束时才会释放,而实例成员没有对象引用时就会释放

②内存中存储的位置不一样

静态成员存放在静态存储区,实例成员在托管堆中。

四,静态类

①静态类被static关键字修饰

 //定义两个静态类static class Person{ }internal static class Cat{ }

②静态类中只能生命静态的成员变量,否则会报错(因为访问该实例成员的时候,类的对象可能还没有被创建

③静态类中不能有实例的构造函数(如果有实例的构造函数,则该静态类能被实例化,都是静态成员,没有实例成员被调用

正确的声明方法:

static class Person{//private int nAge;private static string strName;static Person(){ }}

④静态类不能被继承,反编译刚才的两个类,结果如下:

会发现静态类的本质是一个抽象密封类,所以不能被继承和实例化。所以,静态类的构造函数,不能有访问修饰符

2)那么什么时候声明静态类呢?

如果这个类下面的所有成员的都需要被共享,可以把这个类声明为静态类。

且在一般对象中不能声明静态类型的变量(访问该静态变量时,可能该对象还没有被创建)。

3)静态类的构造函数

静态类可以有静态的构造函数(且所有类都可以有静态的构造函数),如下代码:

class Program{static void Main(string[] args){Cat c;Cat c1 = new Cat();Console.ReadKey();}}class Cat{private int n;public string strName;//实例构造函数public Cat(){Console.WriteLine("看谁先执行2");}//静态构造函数static Cat(){Console.WriteLine("看谁先执行1");}}

执行结果如下:

由此我们可以知道,静态的构造函数会先于实例构造函数执行

            //不执行静态构造函数Cat c;

当我们在Main()函数中添加如下的代码是:

static void Main(string[] args){//不执行静态构造函数
            Cat c;Cat c1 = new Cat();Cat c2 = new Cat();Console.ReadKey();}

运行结果如下:

说明静态的构造函数只执行了一次。

---------------------------------------------分割线-----------------------------------------------

好吧这次的分享风到此结束。希望对大家对理解C#基础概念知识能有所帮助。

转载于:https://www.cnblogs.com/yisuowushinian/p/3537582.html

相关文章:

C#精髓【月儿原创】第一讲 使用垃圾回收器

说明:准备出一个系列,所谓精髓讲C#语言要点。这个系列没有先后顺序,不过尽量做到精。可能会不断增删整理,本系列最原始出处是csdn博客,谢谢关注。 C#精髓 第一讲 使用垃圾回收器 作者:清清月儿 主页:h…

5GtoB即将迎来规模商用,如何共创行业新价值?

4月14日,在华为公司第18届全球分析师大会期间,华为携手运营商代表、产业界代表举办了“5G激发行业新价值”论坛,与行业分析师、金融分析师共同探讨对5GtoB产业未来的展望、创新解决方案以及最佳业务实践。 5G发展进入快车道,融合…

$.ajax上传文件或者上传图片

2019独角兽企业重金招聘Python工程师标准>>> ###FormData 想得到一个FormData对象就必须new一个FormData对象,然后使用append()方法向该对象里添加键值对 var formdata new FormData() //包含用户选择文件的文件流 formdata.append("file",ev…

BMP图形文件分析类(c#)

1using System; 2using JJBase.FILE; 3namespace JJBase.Image 4{ 5 /**//// <summary> 6 /// BMP 的摘要说明。 7 /// </summary> 8 public class BMP 9 { 10 11 public BMP() 12 { 13 // 14 …

gsoap 学习 1-由wsdl文件生成h头文件

开始前先看一下用户向导吧 http://www.cs.fsu.edu/~engelen/soap.html 中左侧点击Documentation 英语水平确实有限,有些内容可能说的不准确,敬请参考向导中原文,以免误导 向导 1.1节中提供了gSoap开发包的下载地址http://sourceforge.net/projects/gsoap2 下载最新gSoap程序包解…

微软每年豪砸安全研发 10 亿美元,聊聊背后的技术密码

从无序中寻找踪迹&#xff0c;从眼前事探索未来。正值 IT 黄金十年新开端&#xff0c; CSDN 欲以中立技术社区专业、客观的角度&#xff0c;深度探讨中国前沿 IT 技术演进&#xff0c;现在推出年度重磅企划——「拟合」&#xff0c;通过对话企业高管大咖&#xff0c;跟踪报道企…

phpstudy多站点配置好后index of/ 列表无法出现的解决

打开配置文件vhost-conf&#xff0c;看到图中画黄色线部分。把新配置的站点中的options后面加上 Indexes 就行了。 转载于:https://www.cnblogs.com/wubuwei/p/7388700.html

【OSX】build AOSP 2.3.7时的build error解决

原始的error log&#xff1a; 1 2 PLATFORM_VERSION_CODENAMEREL3 PLATFORM_VERSION2.3.74 TARGET_PRODUCTgeneric5 TARGET_BUILD_VARIANTeng6 TARGET_SIMULATOR7 TARGET_BUILD_TYPErelease8 TARGET_BUILD_APPS9 TARGET_ARCHarm 10 HOST_ARCHx86 11 HOST_OSdarwin 12 HOST_BUIL…

undefined reference to 'pthread_create'

pthread 库不是 Linux 系统默认的库&#xff0c;连接时需要使用静态库 libpthread.a&#xff0c;所以在使用pthread_create()创建线程&#xff0c;以及调用 pthread_atfork()函数建立fork处理程序时&#xff0c;需要链接该库。源文件&#xff0c;不要忘了加上头文件#include<…

瞄准自然语言处理,百度与鹏城实验室共建实验室

4月16日&#xff0c;百度与鹏城“自然语言处理联合实验室”签约暨揭牌仪式在鹏城实验室举行。 中国工程院院士、鹏城实验室主任高文出席仪式并致辞&#xff0c;鹏城实验室人工智能研究中心主任李革教授和百度集团首席技术官王海峰代表双方介绍了联合实验室前期筹备情况并签署协…

PostgreSQL SQL 语言:并行查询

本文档为PostgreSQL 9.6.0文档&#xff0c;本转载已得到原译者彭煜玮授权。 1. 并行查询如何工作 当优化器判断对于某一个特定的查询&#xff0c;并行查询是最快的执行策略时&#xff0c;优化器将创建一个查询计划。该计划包括一个 Gather 节点。下面是一个简单的例子&#xff…

常用的linux的命令行操作

2019独角兽企业重金招聘Python工程师标准>>> 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI) hdparm -i /dev/hda 罗列一个磁盘的架构特性 hdparm -tT …

Python 极简实现 IoU

来源 | 简明AI头图 | 下载于视觉中国出品 | AI 科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;IOU中文名叫交并比&#xff0c;见名知意就是交集与并集的比值。是在目标检测中常用的算法。IoU原理如上图所示&#xff0c;就是计算上面阴影部分与下面阴影部分的比值。…

静态页htm传参数

//从转向过来的URL中截取参数 开始function SplitUrl(key){var fstrkey;var getstr;var urldocument.URL.toString();urlurl.toLowerCase();//转为小写var locurl.indexOf(fstr);if(loc>0){getstrurl.substring(locfstr.length,url.length);return getstr;}else{return &quo…

vue router 入门笔记

vue router 入门笔记 tips&#xff1a; components优先级大于component&#xff0c;即当一个route对象里同时配置了component和components时component视为无效即使route对象有name属性&#xff0c;也要配置一个path属性。name属性只是配对用的&#xff0c;path是要直接打到url上…

用C#的Raw Socket实现网络封包监视

<script language"javascript" src"/ad/js/edu_left_300-300.js" type"text/javascript"></script> 谈起socket编程&#xff0c;大家也许会想起QQ和IE&#xff0c;没错。还有许多网络工具如P2P、NetMeeting等在应用层实现的应用程序…

人工智能是否能开启人类世界新纪元?

想必许多人都不止一次地幻想过&#xff0c;当人工智能发展到极限时&#xff0c;它将为我们的生活带来多少触手可及的便捷&#xff0c;或是意想不到的惊喜呢&#xff1f;试想一下我们身处英剧《黑镜》的世界中&#xff0c;人类的生活里充斥着人工智能对社交行为的各种评分机制&a…

1月国内操作系统市场:Windows XP份额高达60.84%

IDC评述网&#xff08;idcps.com&#xff09;02月21日报道&#xff1a;据CNZZ数据&#xff0c;在国内操作系统市场上&#xff0c;2014年1月份&#xff0c;微软Windows系统依旧称霸市场&#xff0c;份额为90.63%&#xff0c;环比去年末下滑0.57%。对于市场份额下滑一事&#xff…

17.08.17

控制文件 丢失部分控制文件&#xff1a; SQL> select * from v$controlfile; $ >/u01/app/oracle/oradata/orcl/control01.ctl SQL> select * from v$tablespace; 报错 SQL> alter system checkpoint; 报错 $ vi /u01/app/oracle/diag/rd…

用C#实现基于TCP协议的网络通讯

TCP协议是一个基本的网络协议&#xff0c;基本上所有的网络服务都是基于TCP协议的&#xff0c;如HTTP,FTP等等&#xff0c;所以要了解网络编程就必须了解基于TCP协议的编程。然而TCP协议是一个庞杂的体系&#xff0c;要彻底的弄清楚它的实现不是一天两天的功夫&#xff0c;所幸…

Java NIO系列教程(二) Channel

为什么80%的码农都做不了架构师&#xff1f;>>> Java NIO的通道类似流&#xff0c;但又有些不同&#xff1a; 既可以从通道中读取数据&#xff0c;又可以写数据到通道。但流的读写通常是单向的。通道可以异步地读写。通道中的数据总是要先读到一个Buffer&#xff0…

百度CTO王海峰博鳌解读AI“融合创新”,算力算法数据发挥综合作用

4月18至21日&#xff0c;博鳌亚洲论坛2021年年会在海南博鳌举行。19日下午&#xff0c;百度CTO王海峰受邀参加本届博鳌年会“后疫情时代的人工智能”为主题的圆桌论坛。与公钥加密技术之父、图灵奖得主惠特菲尔德迪菲&#xff0c;阿斯利康公司董事长雷夫约翰森等多位专家和企业…

Java开发工具(Eclipse中内容辅助键的使用)

* A:Alt/ 起提示作用* B:mainalt/,sysoalt/,给出其他提示* C:补充输出语句,选中需要输出的部分,alt/选择最后一项即可* C:定义自己的alt / * windows--perference-Java-Editor-Templates--New * A:新建 ctrl n(new)* B:格式化 ctrlshiftf(format)* C:导入包 ctrlshifto *…

常用的css3的新属性

2019独角兽企业重金招聘Python工程师标准>>> 作为前端开发人员&#xff0c;如果你还不知道或还没有接触过CSS3&#xff0c;那么你真的OUT了&#xff01;就像蒸汽机的发明标志工业革命的开始一样&#xff0c;CSS3和HTML5的出现&#xff0c;将会带来WEB前端开发以及互…

高效分页存储过程

存储过程与页面调用如下&#xff1a; CREATE PROCEDURE search_sptblName varchar(255), -- 表名 strGetFields varchar(1000) *, -- 需要返回的列 fldName varchar(255), -- 排序的字段名 PageSize int 10, -- 页尺寸 PageIndex int , -- 页码 doCount bit 0, -- 返回记录…

2020年企业业务营收同比增长23.0%,华为的数字化转型实践之道

近日&#xff0c;在华为分析师大会期间&#xff0c;华为举办“共创行业新价值”主题峰会&#xff0c;与来自全球的400多名行业分析师、财经分析师、各行业意见领袖及媒体现场参会&#xff0c;分享了对行业趋势的洞察&#xff0c;解决方案在具体行业场景中的实践与探索&#xff…

Neo4j - CQL简介

CQL代表Cypher查询语言。 像Oracle数据库具有查询语言SQL&#xff0c;Neo4j具有CQL作为查询语言。 Neo4j CQL - 它是Neo4j图形数据库的查询语言。它是一种声明性模式匹配语言它遵循SQL语法。它的语法是非常简单且人性化、可读的格式。常用的Neo4j CQL命令&#xff1a; NO.CQL…

String.Format格式说明

C#格式化数值结果表 字符 说明 示例 输出 C货币string.Format("{0:C3}", 2)&#xff04;2.000D十进制string.Format("{0:D3}", 2)002E科学计数法1.20E0011.20E001G常规string.Format("{0:G}", 2)2N用分号隔开的数字string.Format("{…

Azure 中国四年扩容 12 倍还不够,微软放话:全球每年新建 50-100 数据中心!

作者 | 伍杏玲出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;数据已渗透到我们生活和工作的方方面面&#xff0c;如今全球正处于经济发展转型与变革的关键时期&#xff0c;数据作为数字经济的核心生产要素&#xff0c;无疑建设先进的数据中心是科技企业的硬核 IT 实…

.NET中多线程的使用

为什么80%的码农都做不了架构师&#xff1f;>>> 1、不需要传递参数&#xff0c;也不需要返回参数。启动一个线程最直观的办法是实用Thread类。 2、ThreadStart类型的委托&#xff0c;这个委托制定了线程需要执行的方法&#xff1a;method。ThreadStart这个委托定义…