2014年2月4日星期二

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

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
【C#小知识】C#中一些易混淆概念总结(三)  阅读原文»

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

目录:

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

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

一,C#中结构

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

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

public void Result()
public Point(int n)
//Console.WriteLine(n);

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

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

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

031544589875991.png

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

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

//这里可以调用无参数的构造函数

Point p = new Point();

Console.WriteLine(p.GetType());

运行结果如下:

031547574246043.png

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

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

031605364403942.png

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

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

031558338628941.png

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

     //定义构造函数

public Point(int n)

{

this.x = n;

//Console.WriteLine(n);

}

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

031613540498785.png

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

public Point(int n)
//在构造函数中对属性赋值,但是不一定操作字段
//Console.WriteLine(n);

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

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

031627599561858.png

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

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

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

031641484876969.png

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

static void Main(string[] args)
Console.WriteLine(p);
//会调用默认的构造函数对的Point对象初始化
Point p1 = new Point();
Console.WriteLine(p1);

编译的时候会报?div style="border-bottom:1px solid #aaa;margin-bottom:25px">【C#小知识】C#中一些易混淆概念总结(二)  阅读原文»

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

目录:

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

继上篇对一些C#概念问题进行细节的剖析以后,收获颇多。以前,读书的时候,一句话一掠而过,但是现在再去重读的时候,每句话发现都包含大量的信息。这一篇继续总结自己的学习笔记,给大家深度的剖析一些概念性问题,有助于大家对C#的理解。

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

一,构造函数

我们先创建一个类,如下面的代码:

static void Main(string[] args)

然后生成代码。

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

022201265475879.png

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

Console.WriteLine("我是超人!");

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

022210156412070.png

所以,当程序员手动添加了任意类型的构造函数,C#编译器就不会为该类添加默认的构造函数。

构造函数的特点:

①访问修饰符一般是Public②没有返回值,方法名与类名称一致;

二,This关键字的作用

①this关键字代表当前对象,当前运行在内存中的那一个对象。我们添加如下的代码:

private int nAge;
get { return nAge; }
set { nAge = value; }
Console.WriteLine("我是超人!");

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

022232057819481.png

可以看到this关键字代替的就是当前的Person对象。

②this关键字后面跟":"符号,可以调用其它的构造函数

我们再添加如下的代码:

Console.WriteLine("我是超人!");
public Person(int nAge)
Console.WriteLine("超人的年龄{0}", nAge);
//使用this关键字调用了第二个一个参数的构造函数
public Person(int nAge, string strName)
Console.WriteLine("我是叫{0}的超人,年龄{1}", strName, nAge);

我们创建该对象看看是否调用成功。在Main函数中添加如下代码:

  Person p = new Person(10,"强子");  

我们运行代码,看到的打印结果如下:

022239107971538.png

由结果我们可以分析出,当含有两个默认参数的对象创建的时候应该先调用了一个参数的构造函数对对象进行初始化,然后有调用了含有两个参数的构造函数对对象进行初始化。

那么到底是不是这个样子呢?看下边的调试过程:

022245163753351.gif

通过上面的调试过程我们会发现,当构造函数使用this关键字调用其它的构造函数时,首先调用的是该调用的构造函数,在调用被调用的构造函数,先执行被调用的构造函数,在执行直接调用的构造函数。

为什么要这个顺序执行?因为我们默认的传值是10,我们需要打印的超人的年龄是"10",如果先执行直接调用的构造函数,就会被被调用构造函数覆盖。

三,部分类

在同一命名空间下可以使用partial关键字声明相同名称的类(同一命名空间下默认不允许出现相同的类名称),叫做部分类或者伙伴类。

如下图,当在同一命名空间下声明相同名称的类,编译器报错:

022255518289949.png

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

022257594694254.png

分别添加如下的代码:

没有评论:

发表评论