C#易错易混淆知识总结(一)--{.NET平台}{程序集}{Parse Convert}{数据类型的存储位置}{C#方法调用}{属性}
这几天一直在复习C#基础知识,过程中也发现了自己以前理解不清楚和混淆的概念。现在给大家分享出来我的笔记:
一,.NET平台的重要组成部分都是有哪些
1)FCL (所谓的.NET框架类库)
这些类是微软事先定义好的。
例如当我们新创建一个windows窗体应用程序是,VS会帮我们自动生成下面的代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;
这些就是微软事先为程序员定义好的类库。程序员可以直接使用的。
2)CLR (所谓的公共语言运行时)
创建部署.NET程序的必备环境
使用C#,F#,VB等语言都可以来创建.NET应用程序。这时候就需要一个公共语言规范,来把不同的语言解释成.NET FramWork认识的东西。
二,什么是程序集
程序集主要有MSIL组成(所谓的微软中间语言,主要由dll文件组成)
不同编程语言程序被.NET FrameWork编译成程序集(dll文件),当程序需要被执行时,通过CLR中的JIT(及时编译器)编译成本地代码,并将指令发送给CPU执行。
程序集一般有两种:.dll和.exe文件(但是不是所有的dll和exe都叫程序集)
比如:我们在同一个解决方案下,建立多个应用程序或者类库文件。这些程序或者类库编译后就会变成不同的程序集。他们之间是相互独立的。之间如果想要相互访问,需要添加引用。
三,Parse转换和Convert转换的区别
1)Parse转换
①Parse转换只能转换字符串
②自变量是指定的数据类型才可以转换成功
2)Convert转换
①可以转换其他类型(如:类)
②与Parse的区别就是,转换前会对被转换的对象进行判断,如果对象为null则会转换失败
3)TryParse转换
// // 摘要: // 将数字的字符串表示形式转换为它的等效 32 位有符号整数。一个指示转换是否成功的返回值。 // // 参数: // s: // 包含要转换的数字的字符串。 // // result: // 当此方法返回时,如果转换成功,则包含与 s 中所包含的数字等效的 32 位无符号整数值;如果转换失败,则包含零。如果 s 参数为 null 或 System.String.Empty、格式不正确,或者表示的数字小于 // System.Int32.MinValue 或大于 System.Int32.MaxValue,则转换失败。该参数未经初始化即被传递。 // // 返回结果: // 如果成功转换了 s,则为 true;否则为 false。 public static bool TryParse(string s, out Int32 result);
类型转换分为显式转换和隐式转换,两种转换必须都要满足要转换的两个对象的性质必须兼容,若是小的转大的(如int转double)为隐式转换,若大的转小的(double转int)为显示转换,要满足语法【(转换的类型)要转换的内容】,这是针对两个对象兼容的情况,若不兼容,则convert.to【int,double.....】(要转换的内容)如(string转int大的转小的)若string中包含除数字以外的东西的话,则会报错,其本质是调用int.parse方法,所以效率会稍微低点儿,但是int[double,decimal,char].tryparse[要转换的内容,out ***(result)]不会报错,若成功转换,将值给对象,返回true,若不能,返回false,并且有一个方法内部预定义的值。
四,数据类型的存储位置
1)存储在栈中的数据类型
所有数值类型,char,bool,枚举,结构体
2)存储在堆中
string,数组,类
管这些类型,他们的变量的声明都是保存在栈里,真实的对象保存在堆里面,栈里面的变量存储打的是对象的地址。
下面以数组来简单说一下这个问题:
//声明一个一维数组 int[] arr = new int[4];
那么这个表达式的执行顺序是什么呢?
①首先程序会在栈中开辟一段名为arr的int[]类型的空间
②然后在堆中开辟一个int[]对象,再该对象中会有4块连续的内存空间
③堆中的对象返回类型为地址,即new int[4]表达式返回的是地址
示意图如下:
五,C#方法调用
1)带默认参数的方法,默认值必须放在最右侧
下面的写法编译器会报错
2)方法的可变参数
①可变参数被Params
②Params只能用来修饰一维数组
3)方法的out和ref参数
①out参数侧重于输出,必须在方法内对其赋值
②ref参数侧重于修改,但是也可以不修改参数的值
out参数是用在方法中返回多个不同类型的值的时候所使用的,若是单个用return,若是多个相同可以定义一个数组,若是返回多个不同类型,用out,使用前需在方法外定义类型,但是不需要赋值,在方法中则必须为其赋值。
Ref参数,实参和形参都加ref,实参和形参同时改变,本质是将实参和形参的不同内存变成相同的内存空间(形参实参化),使用前为其赋值。
params可变参数,将实参列表中跟可变参数数组类型一致的元素当作数组的元素去处理,params可变参数必须是形参列表中的最后一个元素。
六,属性易混淆点辨别
①属性本身不存值,值是存在这个属性所封装的字段里面
class Study { private int nID; //属性的值存储在封装的字段里面 public int NID { get { return nID; } //这里我们给属性赋值 set { nID = value; } } }
通过访问属性字段获取字段的值
Study stu = new Study();
//通过访问属性字段获取字段的值
int nID = stu.NID;
②属性的返回值类型和字段的值类型没有关系
//属性的值类型为bool private bool gender; //字段的返回类型为string public string Gender { get{return gender==true?"男":"女";} set{gender =value=="男"?true:false;} }
属性的返回值类型决定了get返回值的类型和set参数的类型
//属性的值类型为bool private bool gender; //字段的返回类型为string public string Gender { //get的返回值类型为bool get{return gender==true?"男":"女";} //set参数类型为bool set{gender =value=="男"?true:false;} }
③自动属性到底是怎么回事?
看如下的代码:
//private string strName; //自动属性封装strName public string StrName { get; set; }
这就是所谓的自动属性封装字段。在非自动属性中,程序默认的会有value值来给字段赋值,但是在自动属性中是怎么赋值的呢?
我们使用.NET Reflector反编译来看源代码:
这是我们封转的属性代码:
反编译set函数源代码:
我们可以看到.NET会默认为我们的程序生成一个成员变量<StrName>k__BackingField
get函数的源代码:
返回的也是该成员变量;
那么什么时候可以使用自动属性呢?
如果对一个字段取值和赋值的时候没有任何逻辑验证并且可读可写的时候,就可以使用自动属性。