【C#小知识】C#中一些易混淆概念总结(二)--------构造函数,this关键字,部分类,枚举 分类: C# 2014-02-03 01:24 1576人阅读 评论(0) 收藏
目录:
【C#小知识】C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用
继上篇对一些C#概念问题进行细节的剖析以后,收获颇多。以前,读书的时候,一句话一掠而过,但是现在再去重读的时候,每句话发现都包含大量的信息。这一篇继续总结自己的学习笔记,给大家深度的剖析一些概念性问题,有助于大家对C#的理解。
--------------------------------------------------分割线---------------------------------------------
一,构造函数
我们先创建一个类,如下面的代码:

class Program
{
static void Main(string[] args)
{
}
}
//创建一个Person类
class Person
{ }

然后生成代码。
我们使用.NET Reflector反编译该程序集。会发现该类一被编译,CLR会自动的为该类创建一个默认的构造函数。如下图:

所以在创建该对象的时候,会默认的为该类生成一个无参数的空方法体的构造函数。如果我们不显式的写明构造函数,CLR会为我们调用默认的构造函数。

class Person
{
//声明有实现的构造函数
public Person()
{
Console.WriteLine("我是超人!");
}
}

再次反编译该程序集,会发现添加的构造函数覆盖了C#编译器默认为该类生成的构造函数,如下图:

所以,当程序员手动添加了任意类型的构造函数,C#编译器就不会为该类添加默认的构造函数。
构造函数的特点:
①访问修饰符一般是Public②没有返回值,方法名与类名称一致;
二,This关键字的作用
①this关键字代表当前对象,当前运行在内存中的那一个对象。我们添加如下的代码:

private int nAge;
public int NAge
{
get { return nAge; }
set { nAge = value; }
}
//声明有实现的构造函数
public Person()
{
this.NAge = 100;
Console.WriteLine("我是超人!");
}

这时候我们反编译该程序集,会看到如下结果:

可以看到this关键字代替的就是当前的Person对象。
②this关键字后面跟“:”符号,可以调用其它的构造函数
我们再添加如下的代码:

#region 对象的构造函数
//声明有实现的构造函数
public Person()
{
this.NAge = 100;
Console.WriteLine("我是超人!");
} public Person(int nAge)
{
Console.WriteLine("超人的年龄{0}", nAge);
}
//使用this关键字调用了第二个一个参数的构造函数
public Person(int nAge, string strName)
: this(1)
{
Console.WriteLine("我是叫{0}的超人,年龄{1}", strName, nAge);
}
#endregion

我们创建该对象看看是否调用成功。在Main函数中添加如下代码:
Person p = new Person(10,"强子");
我们运行代码,看到的打印结果如下:

由结果我们可以分析出,当含有两个默认参数的对象创建的时候应该先调用了一个参数的构造函数对对象进行初始化,然后有调用了含有两个参数的构造函数对对象进行初始化。
那么到底是不是这个样子呢?看下边的调试过程:

通过上面的调试过程我们会发现,当构造函数使用this关键字调用其它的构造函数时,首先调用的是该调用的构造函数,在调用被调用的构造函数,先执行被调用的构造函数,在执行直接调用的构造函数。
为什么要这个顺序执行?因为我们默认的传值是10,我们需要打印的超人的年龄是“10”,如果先执行直接调用的构造函数,就会被被调用构造函数覆盖。
三,部分类
在同一命名空间下可以使用partial关键字声明相同名称的类(同一命名空间下默认不允许出现相同的类名称),叫做部分类或者伙伴类。
如下图,当在同一命名空间下声明相同名称的类,编译器报错:

当我们使用Partial关键字时,可以顺利编译通过,如下图:

分别添加如下的代码:

partial class Person
{
private string strAddress; public string StrAddress
{
get { return strAddress; }
set { strAddress = value; }
}
private string strNumber; public string StrNumber
{
get { return strNumber; }
set { strNumber = value; }
} public void Run()
{ }
} partial class Person
{ #region 对象属性
private int nAge; public int NAge
{
get { return nAge; }
set { nAge = value; }
} private string strName; public string StrName
{
get { return strName; }
set { strName = value; }
} #endregion #region 对象的构造函数
//声明有实现的构造函数
public Person()
{
this.NAge = 100;
Console.WriteLine("我是超人!");
} public Person(int nAge)
{
Console.WriteLine("超人的年龄{0}", nAge);
} public Person(int nAge, string strName)
: this(1)
{
Console.WriteLine("我是叫{0}的超人,年龄{1}", strName, nAge);
}
#endregion public void Sing()
{ }
}

我们再次反编译该程序集,会发现如下的结果:

我们会发现使用Partial关键字的两个同名类,被编译成了同一个类。
所以部分类的特点:
①必须在同一个命名空间下的使用Partial关键字的同名类
②部分类其实就是一个类,C#编译器会把它们编译成一个类
③在一个伙伴类中定义的变量可以在另一个伙伴类中访问(因为他们就是一个类)。
四,Const关键字和Readonly关键字的区别
1)const关键字
在Main函数中添加如下的代码:
const string strName = "强子";
Console.WriteLine("我的名字叫{0}",strName);
编译过后,我反编译该程序集发现如下结果:

发现定义的常量并没有出现在反编译的代码中,而且使用Const常量的地方被常量代替了。
2)readonly关键字
添加如下代码:

class cat
{
readonly string reOnlyName = "强子";
public cat()
{
Console.WriteLine(reOnlyName);
}
}

生成后反编译该程序集发现,如下结果:

我们发现被readonly修饰的变量并没有被赋值,这是什么回事呢?我们点击cat类的构造函数时,看到如下结果:

我们发现被readonly修饰的变量是在被调用的时候赋值的。
那么被readonly修饰的变量的是就是不可变的么?当然不是,由反编译的结果我们知道,readonly修饰的变量是在被调用的时候在构造函数中被赋值的,那么我们可以在构造函数中修改readonly的默认值
添加如下代码:

class cat
{
readonly string reOnlyName = "强子";
public cat()
{
this.reOnlyName = "子强";
Console.WriteLine(reOnlyName);
}
}

在Main()函数中添加如下的代码:
cat ct = new cat();
运行结果如下:

说明我们成功在构造函数中修改了readonly变量的值。
readonly和const的区别:
const常量在声明的时候就必须赋初始值,这样声明变量可以提高程序的运行效率。而readonly变量声明时可以不赋初始值,但一定要早构造函数中赋初始值。
也就是说,const变量在编译的时候就要确定常量的值,而readonly是在运行的时候确定该变量的值的。
五,解析枚举
枚举的级别和类的级别一样,可以自定义数据类型,可以在枚举名称后使用“:”来指明枚举类型。看如下代码:

//定义一个方向的枚举类型,枚举成员使用","分割
enum Direction:string
{
east,
west,
south,
north
}

编译会报错,错误信息如下:

由此我们可以知道枚举的数据类型是值类型。
因为枚举是数据类型,所以可以直接声明访问,如下代码:

class Program
{
static void Main(string[] args)
{
//枚举是数据类型可以直接声明
Direction dr = Direction.east; Console.WriteLine(dr); Console.ReadKey();
}
} //定义一个方向的枚举类型,枚举成员使用","分割
enum Direction
{
east,
west,
south,
north
}

也可以这样访问枚举类型

class Program
{
static void Main(string[] args)
{
//枚举是数据类型可以直接声明
// Direction dr = Direction.east; Person p=new Person();
//直接调用枚举变量
p.dir = Direction.east;
Console.WriteLine(p.dir); Console.ReadKey();
}
} class Person
{
private string strName;
//直接声明枚举变量
public Direction dir;
}

每一个枚举成员都对应了一个整型的数值,这个数值默认从0开始递增,可以通过强制转换获取该枚举所代表的值。可以通过如下的代码访问:
Direction dr = Direction.east;
int i = (int)dr;
我们还可以手动为每一个枚举成员赋值,代表的是整型数值,赋值后该枚举成员所代表的值就是所赋的值。如下代码:

enum Direction
{
east=1,
west=0,
south=2,
north=3
}

将字符串转换成枚举
string strDir = "east";
//将字符串转换成枚举类型
Direction d1=(Direction)Enum.Parse(typeof(Direction),strDir);
//转换的时候忽略大小写
Direction d2 = (Direction)Enum.Parse(typeof(Direction), strDir,true);
--------------------------------分割线----------------------------------------
最后我们再来探究一个空指针异常的问题
首先我们先声明一个Dog类:

class Dog
{
private int nAge; public int NAge
{
get { return nAge; }
set { nAge = value; }
}
private string strName; public string StrName
{
get { return strName; }
set { strName = value; }
}
}

在Main()函数中我们这样调用
Dog d = null;
d.StrName = "旺旺";
结果会报错,如下图

我们已经为属性,封装字段了,但是为什么没有办法给字段赋值呢?我们就来探究一下这个问题。
当我们实例化Dog对象,即
Dog d = new Dog();
.NET Framwork做了什么工作呢?如下图:

那为什么会报错呢,原因如下图:

-----------------------------------------------分割线-----------------------------------------------------------------
这次分享到这里就结束了。其实蛮享受写这个过程的。因为在初次的学的时候理解了,如果再写成博客就又加深了印象,最后希望大家都能养成了良好的学习习惯。
毕业实习交流群:221376964。你也可以关注我的新浪微博进行交流。

版权声明:本文为博主原创文章,未经博主允许不得转载。
【C#小知识】C#中一些易混淆概念总结(二)--------构造函数,this关键字,部分类,枚举 分类: C# 2014-02-03 01:24 1576人阅读 评论(0) 收藏的更多相关文章
- 【C#小知识】C#中一些易混淆概念总结(六)---------解析里氏替换原则,虚方法 分类: C# 2014-02-08 01:53 1826人阅读 评论(0) 收藏
目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...
- VS2010中使用命令行参数 分类: c/c++ 2014-07-11 22:24 634人阅读 评论(0) 收藏
在Linux下编程习惯了使用命令行参数,故使用VS2010时也尝试了一下. 新建项目,c++编写程序如下: #include<iostream> #include<fstream&g ...
- ubuntu中安装samba 分类: linux 学习笔记 ubuntu 2015-07-07 16:14 46人阅读 评论(0) 收藏
为了方便的和Windows之间进行交互,samba必不可少. 当然,他的安装使用也很简单: 安装: sudo apt-get install samba sudo apt-get install sm ...
- linux中的帮助命令 分类: linux 学习笔记 ubuntu 2015-07-05 19:07 31人阅读 评论(0) 收藏
说实话,到目前为止我还是不太习惯使用linux自带的帮助文档,遇到问题都是去查我自己下载的chm格式的命令大全,不过这些帮助命令我们还是有必要了解的. 1.man [要查看的命令名称] 例如想要查看l ...
- linux中echo的用法 分类: 学习笔记 linux ubuntu 2015-07-14 14:27 21人阅读 评论(0) 收藏
1.echo命令我们常用的选项有两个,一个是-n,表示输出之后不换行,另外一个是-e,表示对于转义字符按相应的方式处理,如果不加-e那么对于转义字符会按普通字符处理. 2.echo输出时的转义字符 \ ...
- Windows中的DNS服务——正向解析&反向解析配置 分类: AD域 Windows服务 2015-07-16 20:21 19人阅读 评论(0) 收藏
坚信并为之坚持是一切希望的原因. DNS服务是AD域不可或缺的一部分,我们在部署AD域环境时已经搭建了DNS服务(windows server 2008 R2域中的DC部署),但是DNS服务的作用还是 ...
- windows server 2008 R2域中的DC部署 分类: AD域 Windows服务 2015-06-06 21:09 68人阅读 评论(0) 收藏
整个晚上脑子都有点呆滞,想起申请注册好的博客还从来都不曾打理,上来添添生机.从哪里讲起呢,去年有那么一段时间整个人就陷在域里拔不出来,于是整理了一些文档,害怕自己糊里糊涂的脑子将这些东西会在一觉醒来全 ...
- 【C#小知识】C#中一些易混淆概念总结(五)---------继承 分类: C# 2014-02-06 22:05 1106人阅读 评论(0) 收藏
目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...
- 【C#小知识】C#中一些易混淆概念总结(四)---------解析Console.WriteLine() 分类: C# 2014-02-05 17:18 1060人阅读 评论(0) 收藏
目录: [C#小知识]C#中一些易混淆概念总结 [C#小知识]C#中一些易混淆概念总结(二) [C#小知识]C#中一些易混淆概念总结(三) ------------------------------ ...
随机推荐
- Mybatis实现原理探究-实现部分Mybatis功能(上)
一.前言: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简 ...
- Kolakoski
Kolakoski序列:我们知道的还是太少 上帝创造了整数,其余的则是我们人类的事了.正因为如此,质数.完全数.Fibonacci 数之类的数列才会让数学家们如痴如醉,因为它们的存在是如此自然,没有任 ...
- 快速学会在JSP中使用EL表达式
在没有学会EL表达式之前,我们想在JSP文件中获取servlet或者其他JSP页面传来的值,通常都是在JSP页面中编写java代码来实现.而在jsp页面编写Java 代码,这种做法时不规范的,将会产生 ...
- HDU 3472 混合图欧拉回路 + 网络流
九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/13799337 题意: T个测试数据 n串字符 能否倒过来用(1表示能倒着用) 问 ...
- java中的static(包括类前面修饰的static、方法前面修饰的static、成员变量前面修饰的static)
static是静态修饰符: 什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个 ...
- 浏览器中调用PHP在执行linux sudo指令时报sudo: sorry, you must have a tty to run sudo
在php程序中使用了exec函数调用sudo指令,在浏览器中访问后,报sudo: sorry, you must have a tty to run sudo错误. 按照网上搜到的方法,修改/etc/ ...
- HLSL-高级着色语言简介【转】
HLSL-High Level Shader Language 优点 用来书写Vertex Shader和Pixel Shader程序的代码,语法类似于C/C++,在DirectX 8.x的时代,Sh ...
- Font Awesome矢量版,十六进制版,WPF字体使用
我之前在博客中介绍过几个矢量图库网站,在WPF程序中,一般接触到的矢量图标资源有XAML.SVG.字体这三种格式.XAML是标准格式就不说了,SVG并不是直接支持的,不过微软提供了Expression ...
- 基于EasyUi的datagrid合并单元格JS写法
$('#dg').datagrid({ width: 'auto', height: 'auto', scrollbarSize: , queryParams: {}, url: 'kkkk', co ...
- 通过NuGet安装和配置ODP.NET(Oracle Data Provider for .NET)
前言 本文涉及ODP.NET.ODP.NET的托管(managed)驱动.Entity Framework的托管驱动 这三部分的下载.安装.配置. 1.简介 NuGet 是.NET的软件开发包管理工具 ...