我一直在寻找在调用方法(或方法链)时处理空对象的最佳选择。
我们的常见做法是检查条件:
if ( customObject != null ) {
customObject.callMe();
}
使用扩展方法可以进一步改进:
Program customObject = null;
if (customObject.NotNull()) {
customObject.CallMe();
}
public static bool NotNull(this object o) {
return o == null;
}
请注意:我通常会忽略!从我的编程实践。因此,明智地说对我来说扩展方法很好。
然而,在处理涉及Method链的时候,它变得非常复杂。
customObject.CallMe().CallMe2() ex...
您认为如何在C#中处理它,以便仅在CallMe
不为空时调用customObject
,并且仅在CallMe2
返回时调用CallMe
非空对象。
当然我可以使用If条件或三元运算符。但是,我想知道vNext,C#5.0是否有一些东西要提供。
答案 0 :(得分:12)
在即将发布的C#6(vNext)中有?.
运算符(Null条件运算符),它可以轻松地为每个嵌套属性链接空引用检查。
这方面的一个例子是:
int? first = customers?.[0].Orders?.Count();
这是Visual Studio UserVoice站点中的请求功能
您可以在Roslyn的Codeplex网站上查看C#6.0的所有新语言功能的状态:
答案 1 :(得分:4)
您目前可以编写以下类型的扩展方法:
public static class Extensions
{
public static R IfNotNull<T, R>(this T @this, Func<T, R> @select) where T : class
{
return @this.IfNotNull(@select, () => default(R));
}
public static R IfNotNull<T, R>(this T @this, Func<T, R> @select, Func<R> @default) where T : class
{
return @this != null ? @select(@this) : @default();
}
public static void IfNotNull<T>(this T @this, Action<T> @action) where T : class
{
if (@this != null)
{
@action(@this);
}
}
}
然后像这样打电话给他们:
customObject
.IfNotNull(y => y.CallMe())
.IfNotNull(y => y.CallMe2());
答案 2 :(得分:2)
C#5没有提供简化代码的功能。你坚持使用:
然而,作为零传播算子,未来可能会更加明亮?是C#6的一个提议特性,并且有already be implemented is Roslyn,所以如果它在C#6中没有有效的话,那将是一个很大的惊喜。有了这个操作符,你就可以编写了
customObject?.CallMe()?.CallMe2()?.[...]
编译器将为您创建嵌套if(甚至确保每个方法只调用一次)。所以,多一点耐心...
答案 3 :(得分:0)
C#6确实有?
运算符,否则您可以查看monad,尤其是Maybe
monad,例如here,here,elsewhere。是否值得在非功能性语言中使用monad并不是为它们设计的,这是一个不同的问题。
答案 4 :(得分:-6)
这是异常处理的重点。如果您想要回应异常情况,例如从函数返回意外的 null ,那么捕获 NullReferenceException ,并从中调用您的恢复代码那里。异常本身将停止进一步调用,因此如果您希望完成所有操作,请不要执行任何恢复代码。 我不建议这是一个合理的回答,通常至少应记录这样的事情。
try
{
customObject.CallMe().CallMe2()
}
catch (NullReferenceException ex)
{
/* save enough details to determine why you got an unexpected null */
}
不要使用异常处理来完成正常的编程任务,但不要过度避免,通过检查每一个可能的意外事件,无论多么罕见。确定代码中可能出现的故障(您可以做任何事情),并在每个合理大小的块的末尾包含一个健康的 catch 列表。