目录:

【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#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...相关推荐

  1. 【C#小知识】C#中一些易混淆概念总结(七)---------解析抽象类,抽象方法

    目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...

  2. C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用...

    这几天一直在复习C#基础知识,过程中也发现了自己以前理解不清楚和混淆的概念.现在给大家分享出来我的笔记: 一,.NET平台的重要组成部分都是有哪些 1)FCL (所谓的.NET框架类库) 这些类是微软 ...

  3. render在python中的含义_python面试中常见易混淆概念

    可变数据类型和不可变数据类型 基本数据类型都是不可变数据类型 数字,字符串,布尔值,元组 数据结构(容器)都是可变数据类型 列表,字典,集合 不同下划线变量的含义 _单下划线开头:弱"内部使 ...

  4. 小知识 | Java中的“魔数”

    转载自 小知识 | Java中的"魔数" 在编程过程中,我们可能经常听到"魔数"这个词,那么这个词到底指的是什么呢?什么数叫做魔数呢? 一.标识文件类型的&qu ...

  5. java常量和变量 注意事项,建议1: 不要在常量和变量中出现易混淆的字母

    第1章 Java开发中通用的方法和准则 The reasonable man adapts himself to the world;the unreasonable one persists in ...

  6. java语言保留结构和联合_Java 语言中取消了联合概念,保留了结构概念。( )_学小易找答案...

    [单选题]Graves病最严重的临床表现是 [判断题]Java 语言中取消了联合概念,保留了结构概念.( ) [单选题]下列关于子类继承父类的成员的描述中,错误的是 . [多选题]冯.诺依曼机确立计算 ...

  7. 数字电视的几个易混淆概念

      了解数字电视需要分清的五个易混淆概念 2008年北京奥运会一天天在临近,奥组委承诺北京奥运会将使用高清信号直播.为了让全国的观众收看到在自己家门口举行的这一盛大的体育赛事,广电总局已经开始在全国推 ...

  8. c语言冷门小知识,生活中的冷门小知识有哪些

    其实生活中充满了冷门知识,比如喝醋能够防止晕车.花生可以祛牙黄等等.下面是学习啦小编为大家整理的关于生活中的冷门小知识,希望大家喜欢! 生活中的冷门小知识 洗衣机强档比弱档节能 很多人没注意,在同样长 ...

  9. H.264中的一些易混淆概念

    Q:PSNR 峰值信噪比 Q:是根据它来取qp是不是? A:不是, 和QP没有直接关系, 但是QP的选择会影响到PSNR Q: 如果不用率失真最优化, 为什么选择SATD+delta×r(mv,mod ...

最新文章

  1. python使用界面-如何使用python图形化界面wxPython
  2. pythonrequests下载大文件_Python3 使用requests模块显示下载大文件显示进度
  3. Python中最常用的字符串方法!
  4. Winform中使用Timer实现滚动字幕效果(附代码下载)
  5. 大数据+社会化协同 菜鸟不菜成老师
  6. 数学之路-分布式计算-disco(4)
  7. AI算法连载11:统计之集成学习
  8. C语言 数组排序 – 选择法排序 - C语言零基础入门教程
  9. java运行环境jdk的安装和环境变量的配置
  10. JS、javascript计算两个时间差
  11. 从入门到入土:Python实现爬取刷新微博推荐和最新好友微博|cookie调用|模拟登录
  12. 怎么看mac电脑wifi密码?很简单!
  13. 基于51单片机的电子秤设计
  14. 入门软件测试--功能测试
  15. 数据挖掘导论课后习题答案-第七章
  16. LG E900 越狱
  17. 黑苹果 macOS 无法修复磁盘 XXX 已修复
  18. 利用dns特性把普通域用户提升到域管理员权限
  19. referer与referrer
  20. OpenBmc开发错误6:gyp ERR! configure error gyp ERR! stack Error: socket hang up

热门文章

  1. Fedora 15 安装与配置一览
  2. ASP.NET中WebForm组件CheckBoxList编程
  3. FFmpeg中libswresample库简介及测试代码
  4. 海思3536:交叉编译Qt4.8.4
  5. linux驱动:音频驱动(三)ASoc之machine驱动及card初始化
  6. mysql注入实例获取答案_本文实例讲述了MySQL解决SQL注入的另类方法。分享给大家供大家参考,具体如下:问题解读我觉得,这个问题每年带来的成本可以高达数十亿美元了。本文就来谈谈,...
  7. mysql 遍历_MySQL 实现树的遍历详解及简单实现示例
  8. x is y python_Python 基础
  9. python是最好的语言 永远二十岁_Python是世界上最好的语言吗?
  10. hash是线程安全的吗?怎么解决?_这次进程、线程、多线程和线程安全问题,一次性帮你全解决了...