未赋值变量的使用——变通
本文关键字:变通 赋值 变量 | 更新日期: 2023-09-27 18:01:18
我早就知道并习惯了c#中的这种行为,总的来说,我喜欢它。但有时编译器就是不够聪明。
我有一小段代码,现在我的变通方法不是一个大问题,但它可能在类似的情况下。
bool gap=false;
DateTime start; // = new DateTime();
for (int i = 0; i < totaldays; i++)
{
if (gap)
{
if (list[i])
{
var whgap = new WorkHistoryGap();
whgap.From = start; //unassigned variable error
whgap.To = dtFrom.AddDays(i);
return whgap;
}
}
else
{
gap = true;
start = dtFrom.AddDays(i);
}
}
我看到的问题是,如果你必须用一个没有默认构造函数的非空结构体来做这件事呢?如果start
不是一个简单的DateTime对象,是否有办法解决这个问题?
有时候编译器不够聪明
你想让编译器解决的问题相当于停止问题。由于该问题可证明不能由计算机程序解决,我们只做最小的尝试来解决它。我们不做任何特别复杂的事情。你只能忍受了。
有关为什么程序分析等同于停止问题的更多信息,请参阅我关于推断方法的终点是否可达的主题的文章。这本质上与确定一个变量是否被明确赋值是一样的问题;分析非常相似。
http://blogs.msdn.com/b/ericlippert/archive/2011/02/24/never-say-never-part-two.aspx如果您必须对没有默认构造函数的非空结构体执行此操作,该怎么办?
没有这种动物。所有的结构体,无论是否为空,都有一个默认构造函数。
如果start不是一个简单的DateTime对象,会有办法解决这个问题吗?
表达式default(T)
为您提供任何类型t的默认值。您总是可以输入
Foo f = default(Foo);
并具有合法赋值。如果Foo是值类型,则调用默认构造函数,默认构造函数始终存在。如果是引用类型,则返回null
编译器没有办法知道因为gap
变量你保证设置DateTime
直接用
DateTime start = DateTime.Now;
并完成它。
编辑更好的是,再次浏览你的代码时,使用
DateTime start = dtFrom;
在struct
中没有默认构造函数这样的东西。试一试:
struct MyStruct {
public MyStruct() {
// doesn't work
}
}
可以有静态构造函数,但是不能为struct
定义默认构造函数。这就是为什么在很多结构体上都有静态方法Create
,以及为什么你可以用new Point()
来代替Point.Empty
。
任何struct
的"默认构造函数"总是将其所有字段初始化为默认值。某些类型的Empty
静态字段是为了方便。这实际上对性能没有任何影响因为它们都是值类型
在我看来,你的bool gap
和DateTime start
实际上是一样的。试着这样重构:
DateTime? gapStart = null ;
for (int i = 0; i < totaldays; i++)
{
if ( gapStart.HasValue )
{
if (list[i])
{
var whgap = new WorkHistoryGap();
whgap.From = gapStart.Value ; //unassigned variable error
whgap.To = dtFrom.AddDays(i);
return whgap;
}
}
else
{
gapStart = dtFrom.AddDays(i);
}
}
[编辑注:请邮政编码样本,将…哦…]实际上编译。它使它更容易。
[进一步编辑注意:您将gap设置为true,并在第一次通过循环时设置start
值。进一步重构如下:]
DateTime gapStart = dtFrom.AddDays( 0 );
for ( int i = 1 ; i < totaldays ; i++ )
{
if ( list[i] )
{
var whgap = new WorkHistoryGap();
whgap.From = gapStart.Value; //unassigned variable error
whgap.To = dtFrom.AddDays( i );
return whgap;
}
}
为什么要尝试绕过语言的设计?即使编译器可以提前计算出整个循环(这对编译器来说似乎是不必要的复杂),它如何知道不能在部分代码中抛出异常呢?你必须给start
赋值,因为你稍后会在代码中使用它,可能在它(根据你的)不可避免的赋值之前。