惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Last Watchdog
The Last Watchdog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
T
Tor Project blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google DeepMind News
Google DeepMind News
L
LINUX DO - 最新话题
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Vercel News
Vercel News
Last Week in AI
Last Week in AI
月光博客
月光博客
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Proofpoint News Feed
博客园 - 叶小钗
NISL@THU
NISL@THU
C
Check Point Blog
K
Kaspersky official blog
N
News and Events Feed by Topic
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
Arctic Wolf
T
Threatpost
GbyAI
GbyAI
L
LINUX DO - 热门话题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
N
News and Events Feed by Topic
Scott Helme
Scott Helme
P
Privacy International News Feed
The Register - Security
The Register - Security
G
GRAHAM CLULEY
Recorded Future
Recorded Future
Apple Machine Learning Research
Apple Machine Learning Research
C
Cybersecurity and Infrastructure Security Agency CISA
B
Blog
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
Webroot Blog
Webroot Blog
Microsoft Security Blog
Microsoft Security Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
D
DataBreaches.Net
J
Java Code Geeks
AWS News Blog
AWS News Blog
Help Net Security
Help Net Security
Engineering at Meta
Engineering at Meta
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
Google DeepMind News
Google DeepMind News

博客园 - 兵

C#异常处理的方式 CryptoAPI与.NET数字签名类的交互问题 Firefox中Iframe的blur与focus事件问题 .NET中几种基本的线程同步方法 为什么说WinForm的控件只能在主线程中创建和调用 C#与Native C++互相访问 PHP5中的引用 Windows版的PDO太衰了 发现一个FireFox的问题 C#中COM操作(二)---接口查询 C#中COM操作(一)---实例化 非弹出式的模态对话框的背景遮罩 DOTNET事件拾遗 CSS开发辅助工具:Internet Explorer Developer Toolbar 另外一种高效地判断奇数和偶数的方法 如何利用客户端缓存对网站进行优化? 一个多表查询引出的问题(2) 类的成员初始化顺序 一个多表查询引出的问题(1)
Framework里某些类型成员方法的一点疑惑
· 2008-08-08 · via 博客园 - 兵

    前几天我的一个同事在和我交流的时候,提到了这样一个问题:为什么在DateTime里面的一堆AddXXX的成员方法不是作用在实例本身,而是另外返回一个重新实例化的DateTime,在通常的理解上我们看到一个对象的AddXXX的实例方法的时候,第一感觉应该是作用在本身上,即是把本身某个字段的值改变成运算后的值。可是在这里却不遵循这样的“常理”。这样在用的时候,想把一个DateTime的值加上一定的时间的话,很容易就忘了需要重新执行赋值操,导致程序执行的结果和我们预期的不一样。

   我听了之后也同意他的看法,因为自己在写程序的时候,也因为经常忘了这一点而发生类式的“BUG”。回头仔细想了想这个问题,发现类似的还不止DateTime一个,像TimeSpan,DateTimeOffset,甚至于是String的Replace等都是这样的一种情况。非public的方法咱就不说了,没有对外公布里面怎么使用都还可以说得过去,可对外公开的方法还是这样的,就有些不太理解了。

    从上面提到的类型不难看出,这些大都是结构,也就是值类型。虽然String类本身是类类型,但是根据MSDN的说法,由于考虑到在使用上的习惯,String在大部分场合的行为都与值类型一至,因此就行为上来看,Sring大部分的行为仍然是符合值类型的行为,包括赋值,比较,参数传递等。至于为什么String的Replace不是作用在本身上,而是返回一个新的String实例,还有一个原因是String实例分配的内存在构造完成后是只读的,因此想要改变这个值就只能重新生成一个新的实例了。String类的这个方法弄明白了后我们再回到之前提到的那些结构上。这些结构的内部都是由一些简单的值类型组成的,而且从声明的成员字段上来看,都是可以随意改变的。

 1 public struct DateTimeOffset
 2 {
 3     // Fields
 4     private DateTime m_dateTime;
 5     private short m_offsetMinutes;
 6     
 7 }
 8 
 9 public struct DateTime
10 {
11     // Fields
12     private ulong dateData;
13     
14 }
15 
16 public struct TimeSpan
17 {
18     
19     internal long _ticks;
20     
21 }
22 

这就更难理解M$在设计这些类型的时候为什么不把相应的方法(主要指的是AddXXX之类的方法)设计成直接作用在调用的实例本身上而要新生成新的实例了?难道就因为这些类型都是结构,也就是说都是值类型的原因?带着这个疑问我又查看了Framework里面其它常用的结构类型,结果又发现了几个不一样的类型。位于System.Drawing名字空间下的Point(F),Rectangle(F),这几个类型也同样是结构,可是在这些类型上的实例方法,比如说Point(F)的,Offset方法。

1 public void Offset(int dx, int dy)
2 {
3     this.X += dx;
4     this.Y += dy;
5 }
6 public void Offset(Point p)
7 {
8     this.Offset(p.X, p.Y);
9 }

另外还有更“神奇”的是同样是Point(F)里的方法Add却变成了一个静态的方法,而且是重新构造了一个新的Point(F)结构返回,我在这里一点也看不出来为什么这个地方要把Add声明成静态的而不是Point的一个成员方法,功能上这个方法和Offset的那两个方法没有本质上的区别。

1 public static Point Add(Point pt, Size sz)
2 {
3     return new Point(pt.X + sz.Width, pt.Y + sz.Height);
4 }

    同样是结构类型,一部分的方法是把当前对象的值与传入参数运算后构成新的实例返回,而另一部分却直接作用在当前对象本身上,看来上面我猜想的“这样使用的都是结构类型”这种猜测也是不正确的。这两种方式同时出现在Framework里面,感觉好像是随意性比较强,不太符合编程风格的一致性,这只能说明M$自己在写代码的时候也有不遵守规则的地方。