为啥 DateTime.Now 是属性而不是方法?

Posted

技术标签:

【中文标题】为啥 DateTime.Now 是属性而不是方法?【英文标题】:Why is DateTime.Now a property and not a method?为什么 DateTime.Now 是属性而不是方法? 【发布时间】:2011-07-23 05:14:25 【问题描述】:

看完这篇博文:http://wekeroad.com/post/4069048840/when-should-a-method-be-a-property,

我想知道为什么微软选择 C#:

DateTime aDt = DateTime.Now;

而不是

DateTime aDt = DateTime.Now();
最佳实践说:连续两次调用成员时使用方法会产生不同的结果 DateTime.Now 是非确定性方法/属性的完美示例。

你知道这种设计是否有任何理由吗? 或者如果这只是一个小错误?

【问题讨论】:

(Date)时间只是一种幻觉:一切都发生在当下。所以这是一个属性:) 嘿嘿...相对来说,值永远不变;它总是Now。如果结构在其字段中包含不同的数字,则值将相对于 Now!啊……脑……痛…… @Andrew:那么它应该返回 Func<DateTime> 吗? :) 我写了一个程序,在循环中调用DateTime.Now 等待它改变。我可以连续调用它超过 16,000 次而不改变它。使用UtcNow 在它改变之前,我接到了超过 100 万个连续呼叫。我认为这足以使其成为财产。 @Gebe ,我建议约定:“如果连续调用该方法42次返回相同的值-它可以转换为属性。” 【参考方案1】:

在决定“方法与属性”时,建议的测试是“连续调用是否会返回不同的结果”。我建议更好的测试是类似但不相同的问题,“调用例程会影响未来调用相同或不同例程的结果吗?”在大多数情况下,这两个问题的答案是相同的,因为到目前为止,以后调用例程会产生与前一个不同的结果的最常见原因是前者导致后面的调用返回一个不同的结果。

在 DateTime.Now 的情况下,一个调用会影响另一个调用返回的值的唯一方法是,如果第一次调用所花费的执行时间导致第二次调用发生的时间明显晚于其他情况。虽然学究可能会认为时间的流逝是第一次调用的状态改变副作用,但我建议有许多属性需要比 DateTime.Now 更长的时间执行,因此调用其中任何一个都会有更改后续 DateTime.Now 调用返回的值的可能性更大。

请注意,如果“获取时间”例程是一个虚拟类成员而不是一个静态成员,那将改变平衡,使其成为一个方法;虽然“预期的”实现不会影响任何对象的状态,但很可能——或者至少是合理的——某些实现可能会产生副作用。例如,在 RemoteTimeServer 对象上调用 Now 可能会尝试从远程服务器获取时间,并且这种尝试可能会对系统的其余部分产生相当大的副作用(例如,通过导致一台或多台机器缓存 DNS/IP 路由信息,这样下一次访问同一服务器的尝试将快 100 毫秒)。

【讨论】:

【参考方案2】:

它实际上是确定性的;它的输出不是随机的,而是基于可以预测的东西。

“当前时间”一直在变化;所以要在每次调用时相对“相同”,该值必须更改,以便每次调用时,它都会返回当前时间。

编辑:

我突然想到:当然,如果在此期间更改了属性值,则对属性 getter 的两次后续调用可以返回不同的结果。属性不应该是Constants

所以,这就是DateTime.Now 所发生的(概念上);它的值在随后的调用之间被改变。

【讨论】:

实际上它是可以预测的,但在计算机上它确实不是。 Now() 是一个有很多误差范围的函数。我不确定现在是如何指定的,但是使用普通的计时器/时钟,它可以基于实现和硬件实际上返回一个数字,以便 a=DatetTime.Now; b=日期时间。现在; (b-a) 我们得到的输出可能不是,但从概念上讲,“现在”是绝对确定的。不过,我对此并没有真正的看法;我只是觉得这是一个很好的、愚蠢的周五下午问题:P @stefan - 不管怎样,我还没有也不希望为此失眠。 我同意这一点,无论是否回答这个问题,时间都会继续用完...... 您对“确定性”的定义是错误的:“确定性函数在使用一组特定的输入值调用时总是返回相同的结果”。这个词是指是否有可能只给定函数定义和输入来确定输出。使用DateTime.Now 这是不可能的technet.microsoft.com/en-us/library/aa214775(v=sql.80).aspx【参考方案3】:

指南就是这样,而不是硬性规定。

这些准则是针对有状态对象的,实际上是试图说明属性不应该改变对象。 DateTime.Now 是一个静态属性,因此调用它不会改变对象。它也只是反映时间的自然状态,没有改变任何东西。它只是观察一个不断变化的计时器。

所以重点是,不要创建改变对象状态的属性。请务必创建仅观察对象状态的属性(即使状态在外部发生变化)。

作为另一个例子,让我们看一下字符串的长度。这是一个属性,但如果有其他东西从外部更改字符串,则字符串的长度可能会因调用而异。基本上就是这样,计时器正在外部更改,现在只是反映其当前状态,就像 string.Length 或任何其他此类属性一样。

【讨论】:

字符串是不可变的,所以它们的长度不能改变。一个更好的例子是List<T>,如果同时添加或删除了一个元素,其Count 属性可以从一个调用更改为下一个调用。 字符串是不可变的,但这并不意味着它的引用是。这就是为什么我说“如果有其他东西在外部改变了字符串”,我没有说“改变长度”。但你说得有道理。 用StringBuilder代替String,特定实例的长度确实是可变的。顺便说一句,我认为 StringBuilder.Length 应该是一个只读属性,并且应该有 Truncate、Pad 和 SetLength 方法;后两者具有填充字符的可选参数。【参考方案4】:

由于没有关于何时使用方法和属性的明确规定,DateTime.Now 实际上只是读取服务器状态的公开属性,它可能会不断变化,但 DateTime.Now 不会影响状态任何属性,对象或其他什么,所以它是框架中的一个属性。

【讨论】:

除非你考虑海森堡,在海森堡中,仅仅观察某物就会改变它的状态;)【参考方案5】:

我相信通过 C# 实现的 CLR,Jeffrey Richter 提到 DateTime.Now 是一个错误。

System.DateTime 类有一个只读的 Now 属性,返回当前日期和时间。每次查询这个 属性,它将返回不同的值。这是一个错误,微软希望 他们可以通过让 Now 成为方法而不是属性来修复类。

通过 C# 第 3 版的 CLR - 第 243 页

【讨论】:

我一直认为这是一个错误,总是先写 Now(),sigh 至少一次,然后使用两次退格。 我尊重 Jeffrey 和所有这一切,但他没有为此引用消息来源,这让我觉得他在做自己的解释。 DateTime.Now 是一个例外情况,但在所有其他方面都符合准则。我不认为他们会改变这一点,即使他们可以。否则,他们会弃用它并引入一种方法。 我同意这是 Jeffrey 的解释,但我相信他,因为你不能在一个类中拥有同名的属性和方法(因此创建方法并保留已弃用的属性是不可能的) 同样的感叹出现在.NET Framework Design Guidelines中。该书中提供了更详细的理由。任何足够聪明的人都必须阅读这个问题。 ;-) 您引用的书中的摘录是对作者个人意见关于属性的解释的一部分:“就个人而言,我不喜欢属性,我希望这样Microsoft .NET Framework 及其编程语言不支持它们。”我无法给出足够的理由说明为什么这种说法在很多层面上都是错误的。【参考方案6】:

根据 MSDN,当某物是对象的逻辑数据成员时,您应该使用属性:

http://msdn.microsoft.com/en-us/library/bzwdh01d%28VS.71%29.aspx#cpconpropertyusageguidelinesanchor1

继续列出更合适的方法的情况。具有讽刺意味的是,方法的规则之一是在连续调用可能返回不同结果时使用它,当然 Now 肯定符合该标准。

我个人认为这样做是为了消除对额外 () 的需求,但我发现 () 的缺失令人困惑;我花了一点时间才从 VB/VBA 中的旧方法转变。

【讨论】:

以上是关于为啥 DateTime.Now 是属性而不是方法?的主要内容,如果未能解决你的问题,请参考以下文章

python: 为啥 datetime.now() 的 tzinfo 没有? [复制]

DateTime.UtcNow.ToString() 和DateTime.Now.ToString()输出的字符为啥不一样呢?

“DateTime.Now” - 为啥它返回 GMT?

几种Python执行时间的计算方法

运行自定义“时钟”/ DateTime.now c#

C#DateTime.Now precision