为什么不';t t.TryParse返回一个可为null的<;T>;
本文关键字:null gt 一个 lt TryParse 返回 为什么不 | 更新日期: 2023-09-27 18:19:31
据我所知,int.TryParse(string, out int)
存在于Framework 2.0之后。int?
也是如此。
是否有理由使用out
参数而不是返回int?
,其中HasValue
设置为false
的true
,具体取决于转换能力?
原因很简单,因为当int.TryParse
添加到该语言时,Nullable<T>
并不存在。
在Eric Lippert的这篇博客文章中,底部有一行字:
解决方案是编写自己的扩展方法版本的TryParse,就像当初中有可为null的值类型时一样
这清楚地表明在CCD_ 10的原始实现中不可使用可为null的类型。Eric Lippert是编写C#编译器的团队成员,所以我认为这是一个非常权威的来源。
我无法说出实际原因,但我看到了三个可能的原因:
1) 可为null的类型是在.NET 2.0中引入的,而自.NET 1.1以来,第一个TryParse
方法就已经存在了。因此,当引入可为null的类型时,对这样的API更改为时已晚;并且新的类不会以不同的方式实现CCD_ 12,因为已经设置了模式。
2) 并非所有类型都可以与Nullable
结构一起使用,只有值类型可以。但是,有些方法遵循Try*
模式,必须返回引用类型。例如,一个字典可能完全合法地包含null
作为一个项,因此它的TryGetValue
方法需要一种额外的方式来表示没有找到关键字。
3) 按照Try*
-方法的编写方式,可以编写如下代码:
int myValue;
if (int.TryParse("42", out myValue)) {
// do something with myValue
}
// do something else
}
现在,假设TryParse
只返回了一个int?
。您可以丢弃myValue
变量并丢失结果:
if (int.TryParse("42").HasValue) {
// do something with ... what? You didn't store the conversion result!
}
// do something else
}
或者你可以添加一个可以为null的变量:
int? myValue = int.TryParse("42");
if (myValue.HasValue) {
// do something with myValue.Value
}
// do something else
}
这不再是当前版本的优势,相反,它需要在以后的一些实例中写入myValue.Value
,否则一个简单的value
就足够了。请注意,在许多情况下,仅需要有关if
语句的操作是否成功的信息。
这里引用了Julie Lerman的博客(2004年):
我已经在三月份的预览版中使用了
nullable
,但还没有在五月份,当我将使用nullable<t>
与当前选项进行比较时,我对当前的性能(但bcl团队计划进行重大改进!!)感到失望。例如,对于值类型:将
myNullableInt.HasValue
与(在VB中)进行比较是myInt < 0
或参考类型
myNullableThing.HasValue
与"if not myThing=null
"的比较可为null的类型是,目前要慢得多。BCL团队中的一些人曾向我承诺,计划是使可为null的功能更具性能。
我也得到了提示,在未来,以下将是可能的:
Nullable<T> Parse(string value); Nullable<Int32> i = Int32.Parse( some String );
并且将比
TryParse
更具性能。所以这也会很有趣。
我认为一如既往,收益大于成本。
无论如何,在即将到来的C#vNext中,你可以做:
DateTime.TryParse(s, out var parsedDateTime);
将TryParse转换为一行。
另一个可能的原因:
目前形式的.NET和C#的泛型几乎没有发生:这是一个非常接近的决定,而且这个功能几乎没有进入Whidbey(VisualStudio2005)。在数据库上运行CLR代码等功能被赋予了更高的优先级。
最终,将采用泛型的擦除模型,就像Java一样,因为如果没有外部帮助,CLR团队永远不会追求VM中的泛型设计。
来源:http://blogs.msdn.com/b/dsyme/archive/2011/03/15/net-c-generics-history-some-photos-from-feb-1999.aspx
我的观点是:BCL中的大多数更改(或者至少那些与泛型不直接相关的更改)可能需要同时使用带有和不带有泛型的,以防该功能在最终RTM中被剪切。
当然,从调用客户端的角度来看,这也是有道理的:理想情况下,所有的消费语言(好吧,当时没有那么多)都可以使用它们,而out
参数没有泛型那么前沿。
至于原因我们只能猜测,但一些可能的原因是:
赋值开销:一个装箱的值会在内置类型上产生一些(小的)性能开销。
没有实际收益:
int res;
if int.TryParse("one", out res) {
//something
}
不比差多少
int? res = int.TryParse("one");
if (res.HasValue){
int realres = res.Value
//something
}