不知道你看到这个题目会不会很郁闷,但这的确是一个很值得考虑的问题。
你当然会说,这有啥,代码运行一下不就知道啦。
1
DateTime d
=
new
DateTime();
编译虽然通过,但我们要考虑一下,这个d目前是什么值呢?
这就是一个很很值得考虑的问题。
我们知道,如果要声明一个DateTime新实例初始化为指定的年、月和日
使用如下的代码
1
DateTime 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表示的是基督元年
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的默认构造函数。
DateTime的构造函数重载为下表
DateTime (Int64) |
DateTime (Int64, DateTimeKind) |
DateTime (Int32, Int32, Int32) |
DateTime (Int32, Int32, Int32, Calendar) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, Calendar) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, DateTimeKind) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, Int32) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, Int32, Calendar) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, Int32, DateTimeKind) |
DateTime (Int32, Int32, Int32, Int32, Int32, Int32, Int32, Calendar, DateTimeKind) |
的的确确没有默认构造函数,是不是写文档的人不仔细把默认构造函数忘记描述了呢?
当然不是这样的,原因我们来逐步分析
DateTime的定义为:public struct DateTime
我们看到DateTime不是class,而是我们没有看到过的struct(结构)。
结构是一个和class非常接近的数据类型,我们来演示class和struct的区别
以下是对同一个现象描述的class和struct
struct常用来做一个轻量级的类,快速的分配和快速的销毁,但这同时也失去了继承等能力。所以如果你需要类的所有特性,就还是使用类更好。
1
public
struct
StockStruct
2
{
3![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
4
public string Name;
5
public string Code;
6
public double In;
7
public double Out;
8
9
}
10
![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467966/20241018/ecabb2e964754d4291649312febcd80a.gif)
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);
我们为这两个数据类型添加默认构造函数
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![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
11
}
12
![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467966/20241018/ecabb2e964754d4291649312febcd80a.gif)
13
public
class
StockClass
14
{
15
public StockClass()
16
{
17
}
18![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
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![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
13
}
14
![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467966/20241018/ecabb2e964754d4291649312febcd80a.gif)
15
public
class
StockClass
16
{
17
public StockClass(string name, string code)
18
{
19
Name = name;
20
Code = code;
21
}
22![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
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![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
15
}
16
![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467966/20241018/ecabb2e964754d4291649312febcd80a.gif)
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![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
15![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
16
public int CompareTo(object obj)
17
{
18
return -1;
19
}
20![](https://ucc.alicdn.com/gtdqzn4uqwgsg/developer-article467970/20241018/c3518241843f4f66a5cc93249d51ff6c.gif)
21
}
结构可以包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。因为
本文转自shyleoking 51CTO博客,原文链接:http://blog.51cto.com/shyleoking/806257