代码之家  ›  专栏  ›  技术社区  ›  Sergio Tapia

我似乎陷入了一些巨大的麻烦,比如nullreferenceexceptions。

  •  6
  • Sergio Tapia  · 技术社区  · 15 年前

    最近,我开发了一个软件,可以解析和显示网站上的XML信息。很简单,对吧?

    我正在获取大量nullreferenceexceptions。例如,此方法:

    private void SetUserFriends(List<Friend> list)
    {
        int x = 40;
        int y = 3;
    
        if (list != null)
        {
            foreach (Friend friend in list)
            {
                FriendControl control = new FriendControl();
                control.ID = friend.ID;
                control.URL = friend.URL;
                control.SetID(friend.ID);
                control.SetName(friend.Name);
                control.SetImage(friend.Photo);
    
                control.Location = new Point(x, y);
                panel2.Controls.Add(control);
    
                y = y + control.Height + 4;
            } 
        }
    }
    

    为了防止出现异常,我不得不在实际的foreach循环周围包装一个难看得像罪恶的东西。

    我觉得我只是把创可贴贴贴在一个漏气的轮胎上,而不是真正解决问题。我有办法解决这个问题吗?也许我应该读一本关于编程模式的书,或者什么?

    真的,我迷路了。我可能问错了问题。

    6 回复  |  直到 8 年前
        1
  •  15
  •   Michael Petrotta user3140870    15 年前

    听起来,如果在方法中收到错误的参数,您可能不确定该怎么做。您现在所做的并没有本质上的错误,但是更常见的模式是检查方法头中的参数,如果这些参数不是您期望的,则抛出异常:

    if (list == null)
    {
        throw new ArgumentNullException(list);
    }
    

    这是一种常见的防御性编程模式——检查以确保提供的数据通过基本的健全性检查。

    现在,如果您自己显式地调用这个方法,并且发现这个方法接收到一个空值 list 参数当您不期望它时,是时候看看调用方法的逻辑了。我自己,我更喜欢在没有元素时传递空列表,而不是 null ,以避免此类特殊情况。

        2
  •  4
  •   Darko    15 年前

    我可能会被“没有多个出口”的人群否决,但我通常会在方法的开头简单检查一下:

    if (list == null || list.Count == 0) return;
    

    这指定了退出条件,然后您就不需要担心方法中存在多个级别的缩进。只有当你能接受你的列表是空的或者是空的这一事实时,这才有效——这在某些情况下可能发生。

    但我同意codeka,因为你需要看看调用代码,并找出是否可以从中改进它。

        3
  •  2
  •   Matthew King    15 年前

    似乎防御性编程和参数验证是您要寻找的。

    正如其他人所说,简单的参数验证可以为您工作:

    if (list == null)
        throw new ArgumentNullException("list");
    

    或者,如果您厌倦了为每个参数不断地编写这样的检查,那么您可以签出许多开放源码.NET前提条件强制库中的一个。我喜欢 CuttingEdge.Conditions .

    这样,您就可以使用如下内容:

    Condition.Requires(list, "list").IsNotNull();
    

    但是,设置上述任何一种前提条件都只会指定您的方法不接受空值。 你的问题仍然存在于你 将空值传递到方法中!要解决这个问题,您必须检查调用方法的是什么,并找出传入空对象的原因。

        4
  •  1
  •   Spike    15 年前

    除了抛出ArgumentNullException异常之外,还有一个叫做“空obejct模式”的东西,如果您 希望 传递一个空值,例如,表示某个东西不存在,但不想显式地检查空值。本质上,它是一个实现相同接口的存根类,但是它的方法通常是空的,或者返回的值足以使它们完成。 http://en.wikipedia.org/wiki/Null_Object_pattern

    对于不能轻易地表示不存在的值类型(不能为空)也很有用。

        5
  •  0
  •   Matt Mitchell    15 年前

    如果输入无效,我将提前返回(或提前抛出InvalidArgumentException)。

    例如:

    private void SetUserFriends(List<Friend> list) 
    { 
        if (list == null) 
            return;
    
        /* Do stuff */
    }
    

    或者,您可以使用常规的空合并模式:

    private void SetUserFriends(List<Friend> list) 
    { 
        list = list ?? new List<Friend>();
    
        /* Do Stuff */
    }
    
        6
  •  0
  •   jmoreno    8 年前

    你的确问错了问题。正确的问题是“空值是否表示无效的输入或表示x的标志”。

    在向语言中添加非空引用类型并使其成为各种API之前,您可以选择在代码中显式地使用该类型,或者让空引用异常帮助您找到违反期望的位置,然后以某种方式修复数据/代码。