设计选择:我是否希望扩展方法在 null 时抛出异常?

发布于 2024-11-10 18:06:07 字数 1366 浏览 2 评论 0原文

可能的重复:
C#:在扩展中验证“this”参数的最佳实践方法

我对设计选择很矛盾,并且想听听 SO 社区的意见。我在这里举的例子只是必须做出这种设计选择的一种可能情况 - 实际上,可能还有更多情况。欢迎针对此具体案例和更一般的方法提供答案,并且也欢迎关于如何在具体案例中做出决定的指南。

基本上,我想知道如何考虑这一点:当编写一个扩展方法时,如果将空引用作为 this 实例传递,该方法本质上不会失败,是否应该执行空检查是否在参数上?

示例:

我正在 IEnumerable 上编写一个扩展方法,它将迭代集合并执行一些操作Action - 基本上,这就是它要做的事情:

public static void Each<T>(this IEnumerable<T> collection, Action<T> action)
{
    foreach (var t in collection)
    {
        action.Invoke(t);
    }
}

我无法决定的是,如果将 null 传递给任一参数,则此扩展方法应该做什么。如果我不添加任何 null 检查,我将在 action.Invoke(T) 上收到 NullReferenceException,但如果 collectionnull for 循环将默默地不执行任何操作(即使 action 也是 null...也不会引发异常)。

我决定为 action 添加空检查,这样我就可以抛出 ArgumentNullException 而不是 NullReferenceException。但是我想对集合做什么呢?

选项 1: 添加 null 检查,并抛出 ArgumentNullException

选项 2: 只是默默地让该方法不执行任何操作。

当我将来想要使用该方法时,哪一个更有用?为什么?

Possible Duplicate:
C#: Best practice for validating “this” argument in extension methods

I'm ambivalent about a design choice, and would like to hear the opinions of the SO community. The example I bring up here is just one possible case where this design choice has to be made - in reality, there might be many more cases. Answers are welcome both to this specific case and to a more general approach, and guidelines on how to make the decision in a specific case are also appreciated.

Basically, I want to know how to think about this: When writing an extension method that doesn't intrinsically fail if a null reference is passed as the this instance, should a null check be performed on the argument or not?

Example:

I'm writing an extension method on IEnumerable<T> that will iterate through the collection and performe some Action<T> - basically, this is what it'll do:

public static void Each<T>(this IEnumerable<T> collection, Action<T> action)
{
    foreach (var t in collection)
    {
        action.Invoke(t);
    }
}

What I cannot decide about, is what this extension method should do if null is passed into either parameter. If I do not add any null checks, I will get a NullReferenceException on action.Invoke(T), but if collection is null the for loop will just silently do nothing (and no exception will be thrown even if action is also null...).

I am quite decided to add a null check for action, so I can throw an ArgumentNullException instead of the NullReferenceException. But what do I want to do about the collection?

Option 1: Add a null check, and throw ArgumentNullException.

Option 2: Just silently let the method do nothing.

Which will be more useful where I might want to use the method in the future? Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

半边脸i 2024-11-17 18:06:07

如果 LINQ 中调用的集合为空,则 Microsoft 会引发 ArgumentNullException。这实际上更多是一个风格问题,但与扩展方法应该表现的方式一致。

@m0sa 是对的,因为你将从 foreach 中获得空引用,但我会说检查顶部并抛出 ArgumentNullException。这样您就可以与 LINQ 的功能相媲美。

例如,如果您在反编译器中查看 Any(),您会看到:

public static bool Any<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            return true;
        }
    }
    return false;
}

Microsoft throws an ArgumentNullException if the collections invoked in LINQ are empty. This is really more a matter of style, but is consistent with the way extension methods are supposed to behave.

@m0sa is right though in that you'll get a null reference from your foreach, but I would say check up top and throw ArgumentNullException. That way you'll be on par with what LINQ does.

For example, if you look at Any() in a decompiler you see:

public static bool Any<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            return true;
        }
    }
    return false;
}
漫漫岁月 2024-11-17 18:06:07

您绝对应该进行 null 检查并抛出 ArgumentNullException 以避免代码中难以理解的 NullReferenceExceptions

一般来说,我会避免将 null 视为“空”IEnumerable。只需使用 Enumerable.Empty() 即可避免 null 集合出现特殊情况。

如果您决定在扩展方法中进行 null 检查,您应该考虑“热切地”这样做。如果您在扩展方法中使用yield return,则在迭代开始之前,实际上不会评估任何内容。您将扩展方法分为两部分。检查参数的“急切”部分和产生返回元素的“惰性”部分。

You should definitely do null checking and throw ArgumentNullException to avoid hard to understand NullReferenceExceptions inside your code.

In general I would avoid to treat null as en "empty" IEnumerable<T>. Just use Enumerable.Empty<T>() instead to avoid special cases for a null collection.

If you decide to do null checking in your extension method you should consider doing that "eagerly". If you are using yield return inside your extension method none of it will actually be evaluated until iteration begins. You split your extension method into two parts. The "eager" part where arguments are checked and the "lazy" that yield return elements.

樱花细雨 2024-11-17 18:06:07

首先:我非常确定,如果 collectionnull,将会出现 NullReferenceException。所以你的问题的这一部分根本没有问题。关于其余的:通过检查 null 并抛出不同的异常,您可以获得任何好处吗?我认为:不!所以我不会用根本没有帮助的检查来扰乱我的代码。

First of all: I'm quite sure that there will be an NullReferenceException if collection is null. So that part of your question is no problem at all. Regarding the rest: Do you gain anything by checking for null and throwing a different exception? In my opinion: no! So I would not clutter my code with checks that do not help at all.

美胚控场 2024-11-17 18:06:07

如果集合参数为 null,我会抛出 NullReferenceException。这是因为,如果它是 null,并且 Each 恰好只是一个常规方法,那么它会如何表现——一个 NullReferenceException > 被扔掉是我所期望发生的事情。

编辑
根据马丁的评论和对此的一些进一步研究,我收回我所说的话。似乎 NullReferenceException 在这种情况下不应抛出,如 Microsoft 建议使用 ArgumentNullException 代替。

If the collection argument was null I would throw a NullReferenceException. This comes from thinking about how it would behave if it was null, and Each<T> happened to be just a regular method--a NullReferenceException being thrown is what I would expect to happen.

EDIT:
Based on Martin's comment and some further research on this, I take back what I said. It seems that a NullReferenceException shouldn't be thrown in this case, as Microsoft recommends using an ArgumentNullException instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文