从.Net 2.0升级到.Net 4.5.2后,出现了String.Format异常

8

我最近将一个ASP.Net表单应用程序升级到了.Net 4.5.2,修复了一些相对不重要的命名空间问题后,我成功地构建了解决方案。然而,在运行时,我一直收到以下错误:

'mscorlib.dll'中发生了'Type:System.FormatException'的未处理异常

调试时,此错误由以下行引发:

string.Format("Init took {0:mm:ss}", (object) DateTime.Now.Subtract(renderStartTime))  

当renderStartTime = DateTime.Now时

自从升级以来,我有些困惑为什么会出现这个错误。你有什么想法吗?


移除对象的强制转换。 - Federico Berasategui
3
同意 @HighCore 的说法,这是一个不必要的转换,但即使没有它,异常仍然会被抛出。 - Matt
3
根据这里给出的答案,从.NET 3.5到.NET 4.0,在格式化TimeSpan时发生了破坏性更改。 - Jonesopolis
请检查我的解决方案,如果有不清楚的地方,请告诉我。 - mybirthname
3个回答

6

这是一项重大更改。

请参见:在.NET Framework 4中格式化和解析时间间隔

.NET Framework 3.5及早期版本中,TimeSpan不实现IFormattable,也不支持格式字符串。因此,“r”格式字符串被忽略,调用无参数的TimeSpan.ToString方法。然而,在.NET Framework 4中,将调用TimeSpan.ToString(String, IFormatProvider)并传递不受支持的格式字符串,这会导致异常。

为了扩展答案,您在.NET Framework 2.0中的原始代码不会引发异常,但它不会给出所需的输出(分钟数:秒数)。由于TimeSpan将调用无参数构造函数,忽略String.Format中指定的格式。但是,在.NET Framework 4.0或更高版本中,由于TimeSpan实现了IFormattable,因此指定的格式mm:ss将传递给ToString调用。现在,这个格式mm:ss对于TimeSpan是无效的,它需要使用反斜杠来转义冒号,如:mm\:ss。这就是为什么会出现异常的原因。

请参见:自定义TimeSpan格式字符串

在.NET 3.5或更低版本中,您可以使用:

TimeSpan elapsed = DateTime.Now - renderStartTime; //or DateTime.Now.Subtract(renderStartTime)
string formatted = string.Format("Init took {0}:{1}", elapsed.Minutes, elapsed.Seconds); //returns minutes and seconds components, 
                                        // If you are looking for Total Minutes and Total Seconds then use TotalMinutes/TotalSeconds

在 .Net Framework 4.0 或更高版本中,你可以这样做:
string.Format("Init took {0:mm\\:ss}", elapsed);

3
问题出在第二个冒号。你可以尝试以下方法代替:
string.Format("Init took {0:mm}:{0:ss}", DateTime.Now.Subtract(renderStartTime));

编辑

根据在 .Net 3.5 及更早版本中的 TimeSpan 的工作方式,原始 .Net 2.0 中的代码实际上会以 hh:mm:ss 的格式打印出时间。基本上,格式的 "mm:ss" 部分被忽略了,因为 TimeSpan 没有实现 IFormattable 接口。因此,在 .Net 4.5.2 中,以下代码更接近于替换 .Net 2.0 中的原始代码。

string.Format("Init took {0}", DateTime.Now.Subtract(renderStartTime));

但是,如果你只想显示分钟和秒数,你可以使用以下格式之一:{0:mm}:{0:ss}{0:mm\\:ss} 在 .Net 4.0 及更高版本中。或者在 .Net 3.5 或更早的版本中,你需要这样做。

TimeSpan diff = DateTime.Now.Subtract(renderStartTime);
string.Format("Init took {0:00}:{1:00}", diff.Minutes, diff.Seconds);

这段代码在 .Net 2.0 中无法返回预期值。对于框架版本 4.0 或更高版本,即使使用 string.Format("Init took {0:mm\\:ss}", DateTime.Now.Subtract(renderStartTime)); 就足够了,但是在 .Net 3.5 及以下版本中无法正常工作 :) - Habib
@Habib 是的,我原始代码中的2.0版本只返回了分钟和秒数。 - juharr

3
 Console.WriteLine(string.Format("Init took {0:mm\\:ss}", DateTime.Now.Subtract(renderStartTime)));

在这里,您需要让代码看起来像这样。如果您愿意,可以这样做。

 Console.WriteLine(string.Format(@"Init took {0:mm\:ss}", DateTime.Now.Subtract(renderStartTime)));

您可以阅读这份微软文档获取更多帮助:
自定义TimeSpan格式说明符不包含占位分隔符,例如将天数与小时、小时与分钟或秒与分数秒分开的符号。相反,这些符号必须作为字符串文字包含在自定义格式字符串中。例如,“dd.hh:mm”定义了一个句点(.)作为天数和小时之间的分隔符,而冒号(:)则是小时和分钟之间的分隔符。自定义TimeSpan格式说明符也不包括一个符号,用以区分负时间间隔和正时间间隔。要包含符号,必须使用条件逻辑构建格式字符串。其他字符部分包括一个示例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接