首先,我知道这个问题可以通过一个简单的回答回答,即空字符串不是空值。此外,我最近才通过另一个stackoverflow问题在今年早些时候发现了演员操作员,并且没有很多经验。即使如此,当与空合并运算符结合使用时,这些转换运算符并不完全那么简单的原因被称为处理LINQ表达式中缺少元素或属性等错误条件的优雅解决方案。我开始使用the approach described by ScottH in "Improving LINQ Code Smell..."和ScottGu "Null coalescing operator (and using it with LINQ)"作为一种以简洁和半优雅的方式防范无效/丢失数据的方法。从我可以收集的内容看来,这似乎是将所有转换重载放在LINQ类中的动机之一。
因此,在我看来,处理缺失值的用例与处理空值并不完全不同,在链接文章中,这种方法被认为是处理这种情况的好方法
情景:
int length = (int?)elem.Attribute("Length") ?? 0;
如果缺少@Length属性,则强制转换为空值并且运算符返回0;
如果@Length属性存在但是为空,则转换内部在int.tryparse上分支并抛出格式异常。当然,对于我的用法,我希望它不会,并且只是返回null,所以我可以继续在我已经有些复杂的LINQ代码中使用这种方法。
最终,我不能提出一个解决方案,但更多的是我有兴趣听到是否有一个我错过的明显方法,或者是否有人对错过的原因有很好的认识价值情景得到了解决,但空值情景却没有。
修改
似乎有一些关键点我应该尝试并强调:
链接文章来自MS工作人员,我很钦佩并寻求指导。这些文章似乎提出(或至少提请注意)处理可选值的改进/替代方法
在我的情况下,可选值有时以缺少元素或属性的形式出现,但也以空的形式出现元素或价值
所描述的方法对于缺失值起作用,但对于空值失败
遵循所描述的方法的代码似乎是在防止缺少可选值,但实际上是脆弱的并且在特定情况下会中断。事实上,你仍然面临着与我有关的风险
如果目标元素存在但是为空,则可以通过声明两个链接的示例都因运行时异常而失败来突出显示
最后,似乎关键的一点是,当您签订合同(可能通过架构)时,所描述的方法很有效,可确保元素或属性永远为空但在如果该合同不存在,这种方法无效,需要替代方案
答案 0 :(得分:3)
我同意这种行为;如果我没有一个“id”属性/元素,那么我很高兴将其视为null,但如果它存在但不解析,那么是不同的 - 一个空字符串适用于很少的类型。你必须手动完成,或者你可以在XAttribute
等上添加扩展方法:
public static int? ParseInt32(this XAttribute attrib) {
if(attrib != null && string.IsNullOrEmpty(attrib.Value)) return null;
return (int?)attrib;
}
注意我在内部使用强制转换为虽然int
很简单,但.Parse
对DateTime
等来说是一个不好的例子,在xml中使用不同的格式,转换在内部处理。
答案 1 :(得分:1)
就解决方法而言,我已经在下面构建了扩展方法。我没有想到Marc描述的方法用可以为空的int修复问题并且仍然使用??用于指定默认值的运算符。非常有创意,并允许X ?? Y模式继续使用。
我认为最后我可能更喜欢Marc的方法,因为它在我的赋值语句中保持一致的模式,并没有引入TryParseInt调用所具有的语法混淆,因为它看起来太像你解析-1或者默认的/ fallback值已提供。
elem.Attribute("ID").TryParseInt(-1)
/// <summary>
/// Parses an attribute to extract an In32 value and falls back to the defaultValue should parsing fail
/// </summary>
/// <param name="defaultValue">The value to use should Int32.TryParse fail</param>
/// <returns>The parsed or default integer value</returns>
public static int TryParseInt(this XAttribute attr, int defaultValue)
{
int result;
if (!Int32.TryParse((string)attr, out result))
{
// When parsing fails, use the fallback value
result = defaultValue;
}
return result;
}