子对象上的 C# null 检查扩展方法不起作用 [duplicate]

C# null checking extension method on sub-object does not work [duplicate]

提问人:Nick 提问时间:10/18/2023 更新时间:10/18/2023 访问量:68

问:

我有一个 null 检查扩展方法

public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

最好调用以避免在运行循环之前进行额外的 null 检查,如下所示

int[] intArray = new int[] { 1, 2, 3 };
int sum = 0;
foreach (int i in intArray.OrEmptyIfNull())
    sum += i;

但是,如果我使用的 IEnumerable 位于另一个对象内,如果周围的对象为 null,它将失败并显示 NullReferenceException - 如下所示

foreach (int i in object?.intArray.OrEmptyIfNull())
    sum += i;

阅读 In C# 中的讨论后,在 null 对象上调用扩展方法时会发生什么情况?我知道编译器将表达式转换为

ExtensionClass.OrEmptyIfNull(object?.intArray)

但是如果对象==null,我在这里遇到NullReferenceException。 为什么?

这种行为不会使任何使用 null 检查扩展方法变得非常危险吗?

C# 扩展方法 NullReferenceException

评论

2赞 madreflection 10/18/2023
(object?.intArray).OrEmptyIfNull()
0赞 madreflection 10/18/2023
“编译器将表达式转换为......” - 由于短路,它不会转换为该表达式。
0赞 mm8 10/18/2023
由于短路,如果为 null,则永远不会调用您的方法,即表达式始终为 if 为 null。objectobject?.intArray.OrEmptyIfNull()nullobject
0赞 lidqy 10/18/2023
您可以在 foreach 之前执行 null 检查,从而通过不创建不可枚举的可枚举对象来节省 CPU 周期
0赞 Nick 10/18/2023
如果关心一些CPU周期,最好做C++而不是.net......

答:

-1赞 JP Alioto 10/18/2023 #1

我认为您在可为 null 的引用类型和可为 null 的值类型之间感到困惑。

可为 null 的引用类型就是该类型。由于是引用类型,因此您只有一个对象。如果取消引用 null 引用类型,则会出现异常。如果您知道在运行时不为 null 的事实,则可以使用语法 ...objectobject

对象!。intArray (整数组)

例如。但是,你为什么要这样做呢?显然,在您的例子中,对象是 null。只需检查一下。

评论

0赞 Nick 10/18/2023
我的目的是在对可能为 null 的枚举对象执行循环之前避免使用 if 语句。在这种情况下,我显然不能应用这种方法:-((
0赞 JP Alioto 10/18/2023
@Nick null 的不是 intArray,而是 object。
0赞 Nick 10/18/2023
最终的解决方案是在运行循环之前添加 if,或者像 @madreflection 建议的那样插入括号:(object?.intArray)。OrEmptyIfNull()
3赞 mm8 10/18/2023 #2

由于短路,从不调用您的扩展方法 if is,即表达式始终是 if is 。 在这种情况下甚至没有评估。objectnullobject?.intArray.OrEmptyIfNull()nullobjectnullintArray

一个更简洁的方法是在尝试迭代之前实际检查引用:

if (object?.intArray != null)
    foreach (int i in object.intArray)
        ...

或者,至少在这种特殊情况下,您始终可以使用 LINQ:

int sum = object?.intArray?.Sum() ?? 0;

评论

0赞 Nick 10/18/2023
这回答了我的“为什么”问题。我的目的是在对可能为 null 的枚举对象执行循环之前避免使用 if 语句。所以你的解决方案是显而易见的,但只是说我的方法在它是子对象的情况下没有意义。我的第二个问题是否危险,引出有什么最佳实践?
0赞 mm8 10/18/2023
我想这是基于意见的,但 IMO 最好的解决方案是始终检查是否是,而不是依赖扩展方法的实现。IEnumerablenull