不知道你看到这个题目会不会很郁闷,但这的确是一个很值得考虑的问题。
你当然会说,这有啥,代码运行一下不就知道啦。
这就是一个很很值得考虑的问题。
我们知道,如果要声明一个DateTime新实例初始化为指定的年、月和日
使用如下的代码
但事实是
DateTime的构造函数重载为下表
我们分别实例化,代码的运行完全一样
我们为这两个数据类型添加默认构造函数
我们发现不能为struct添加显式的无参数构造函数,这是为什么呢?简单的说,你可以这样理解:
class默认没有构造函数,当你一个构造函数都不写得时候,编译器会给你的类添加一个默认的构造函数。
struct天生有一个默认构造函数,该构造函数是由编译器统一控制,所以你就不能再为结构编写默认构造函数了。
我们再次修改我们的代码
以上代码看似没有什么错误,但编译的结构再次让你感到沮丧。
class的代码被编译通过了,struct又有错误了
在控制离开构造函数之前,字段“StockStruct.In”必须完全赋值
在控制离开构造函数之前,字段“StockStruct.Out”必须完全赋值
该错误提示告诉我们,要么我们不给struct编写构造函数,编译器使用各数据类型的默认值,如果我们编写了构造函数,就必须在构造函数中为该struct的所有数据成员完全赋值。
这其实就是值类型和引用类型的一个区别:
值类型,要求在编译时知道对象的大小,引用类型可以推迟到运行时才知道对象的大小。
struct是值类型,因此又推导出另一个特征:struct没有析构函数。
上面的代码又错了,struct要求不能从其他类或结构继承,其他结构和类也不允许继承结构(结构天然的就是一个密封类型)。同时推导:struct 不能为 abstract,而应始终为隐式 sealed。
不过,结构仅可以支持接口,所以同时推导:结构成员无法声明为protected。
结构可以包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。因为struct常用来做一个轻量级的类,快速的分配和快速的销毁,但这同时也失去了继承等能力。所以如果你需要类的所有特性,就还是使用类更好。
你当然会说,这有啥,代码运行一下不就知道啦。
1DateTime d = new DateTime();
编译虽然通过,但我们要考虑一下,这个d目前是什么值呢?这就是一个很很值得考虑的问题。
我们知道,如果要声明一个DateTime新实例初始化为指定的年、月和日
使用如下的代码
1DateTime d = new DateTime(2007,1,1);
那么,按一般我们对类的设计方法,DateTime的默认构造函数返回当前的日期实例比较合理。但事实是
1 DateTime d = new DateTime();
2 System.Console.WriteLine(d);//0001-1-1 0:00:00
日期0001-1-1 0:00:00表示的是基督元年2 System.Console.WriteLine(d);//0001-1-1 0:00:00
1 DateTime d = new DateTime();
2 System.Console.WriteLine(d);//0001-1-1 0:00:00
3 System.Console.WriteLine(DateTime.MinValue);//0001-1-1 0:00:00
不过,事情到这里还没有结束,感觉上我们使用DateTime的默认构造函数产生了基督元年,但你去查一下DateTime的帮助,你会吓一跳,文档上根本没有声明过DateTime的默认构造函数。2 System.Console.WriteLine(d);//0001-1-1 0:00:00
3 System.Console.WriteLine(DateTime.MinValue);//0001-1-1 0:00:00
DateTime的构造函数重载为下表
的的确确没有默认构造函数,是不是写文档的人不仔细把默认构造函数忘记描述了呢?
当然不是这样的,原因我们来逐步分析
DateTime的定义为:public struct DateTime
我们看到DateTime不是class,而是我们没有看到过的struct(结构)。
结构是一个和class非常接近的数据类型,我们来演示class和struct的区别
以下是对同一个现象描述的class和struct
1 public struct StockStruct
2 {
3
4 public string Name;
5 public string Code;
6 public double In;
7 public double Out;
8
9 }
10
11 public class StockClass
12 {
13 public string Name;
14 public string Code;
15 public double In;
16 public double Out;
17 }
2 {
3
4 public string Name;
5 public string Code;
6 public double In;
7 public double Out;
8
9 }
10
11 public class StockClass
12 {
13 public string Name;
14 public string Code;
15 public double In;
16 public double Out;
17 }
我们分别实例化,代码的运行完全一样
1 StockStruct ss = new StockStruct();
2 System.Console.WriteLine(ss.Name);
3 StockClass sc = new StockClass();
4 System.Console.WriteLine(sc.Name);
2 System.Console.WriteLine(ss.Name);
3 StockClass sc = new StockClass();
4 System.Console.WriteLine(sc.Name);
我们为这两个数据类型添加默认构造函数
1 public struct StockStruct
2 {
3 /*结构不能包含显式的无参数构造函数
4 public StockStruct()
{
5 }
*/
6 public string Name;
7 public string Code;
8 public double In;
9 public double Out;
10
11 }
12
13 public class StockClass
14 {
15 public StockClass()
16 {
17 }
18
19 public string Name;
20 public string Code;
21 public double In;
22 public double Out;
23 }
2 {
3 /*结构不能包含显式的无参数构造函数
4 public StockStruct()
{
5 }
*/
6 public string Name;
7 public string Code;
8 public double In;
9 public double Out;
10
11 }
12
13 public class StockClass
14 {
15 public StockClass()
16 {
17 }
18
19 public string Name;
20 public string Code;
21 public double In;
22 public double Out;
23 }
我们发现不能为struct添加显式的无参数构造函数,这是为什么呢?简单的说,你可以这样理解:
class默认没有构造函数,当你一个构造函数都不写得时候,编译器会给你的类添加一个默认的构造函数。
struct天生有一个默认构造函数,该构造函数是由编译器统一控制,所以你就不能再为结构编写默认构造函数了。
我们再次修改我们的代码
1 public struct StockStruct
2 {
3 public StockStruct(string name,string code)
4 {
5 Name = name;
6 Code = code;
7 }
8 public string Name;
9 public string Code;
10 public double In;
11 public double Out;
12
13 }
14
15 public class StockClass
16 {
17 public StockClass(string name, string code)
18 {
19 Name = name;
20 Code = code;
21 }
22
23 public string Name;
24 public string Code;
25 public double In;
26 public double Out;
27 }
2 {
3 public StockStruct(string name,string code)
4 {
5 Name = name;
6 Code = code;
7 }
8 public string Name;
9 public string Code;
10 public double In;
11 public double Out;
12
13 }
14
15 public class StockClass
16 {
17 public StockClass(string name, string code)
18 {
19 Name = name;
20 Code = code;
21 }
22
23 public string Name;
24 public string Code;
25 public double In;
26 public double Out;
27 }
以上代码看似没有什么错误,但编译的结构再次让你感到沮丧。
class的代码被编译通过了,struct又有错误了
在控制离开构造函数之前,字段“StockStruct.In”必须完全赋值
在控制离开构造函数之前,字段“StockStruct.Out”必须完全赋值
该错误提示告诉我们,要么我们不给struct编写构造函数,编译器使用各数据类型的默认值,如果我们编写了构造函数,就必须在构造函数中为该struct的所有数据成员完全赋值。
这其实就是值类型和引用类型的一个区别:
值类型,要求在编译时知道对象的大小,引用类型可以推迟到运行时才知道对象的大小。
struct是值类型,因此又推导出另一个特征:struct没有析构函数。
1 public struct StockStruct : Object
2 {
3 public StockStruct(string name,string code)
4 {
5 Name = name;
6 Code = code;
7 In = 0;
8 Out = 0;
9 }
10 public string Name;
11 public string Code;
12 public double In;
13 public double Out;
14
15 }
16
17 public struct HKStock : StockStruct
18 {
19
20 }
2 {
3 public StockStruct(string name,string code)
4 {
5 Name = name;
6 Code = code;
7 In = 0;
8 Out = 0;
9 }
10 public string Name;
11 public string Code;
12 public double In;
13 public double Out;
14
15 }
16
17 public struct HKStock : StockStruct
18 {
19
20 }
上面的代码又错了,struct要求不能从其他类或结构继承,其他结构和类也不允许继承结构(结构天然的就是一个密封类型)。同时推导:struct 不能为 abstract,而应始终为隐式 sealed。
不过,结构仅可以支持接口,所以同时推导:结构成员无法声明为protected。
1 public struct StockStruct : System.IComparable
2 {
3 public StockStruct(string name, string code)
4 {
5 Name = name;
6 Code = code;
7 In = 0;
8 Out = 0;
9 }
10 public string Name;
11 public string Code;
12 public double In;
13 public double Out;
14
15
16 public int CompareTo(object obj)
17 {
18 return -1;
19 }
20
21 }
2 {
3 public StockStruct(string name, string code)
4 {
5 Name = name;
6 Code = code;
7 In = 0;
8 Out = 0;
9 }
10 public string Name;
11 public string Code;
12 public double In;
13 public double Out;
14
15
16 public int CompareTo(object obj)
17 {
18 return -1;
19 }
20
21 }
结构可以包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。因为struct常用来做一个轻量级的类,快速的分配和快速的销毁,但这同时也失去了继承等能力。所以如果你需要类的所有特性,就还是使用类更好。