默认字符串初始化:NULL还是空?

138

我一直将字符串初始化为NULL,认为NULL表示缺少值,“”或String.Empty是有效值。最近我看到了更多的代码示例,其中String.Empty被认为是默认值或没有值的代表。这让我感到奇怪,因为在c#中新增了可空类型,似乎我们正在通过不使用NULL来表示“无值”而倒退。

你使用什么作为默认初始化程序?为什么?

编辑:根据答案我进一步思考

  1. 避免错误处理 如果该值不应该为null,那么它为什么首先被设置为NULL?也许在发生错误的地方识别错误比遍布整个代码库更好?

  2. 避免null检查 如果您厌倦了在代码中进行null检查,是否最好抽象出null检查?也许包装(或扩展!)字符串方法以使它们NULL安全会更好?如果您不断使用String.Empty并且空值成功进入系统,那么您会开始添加NULL检查吗?

我不能帮助但回到这种想法是懒惰的观点。任何DBA都会在他/她的数据库中使用''而不是null时拍打你。我认为在编程中应该适用相同的原则,应该有人敲打那些使用String.Empty而不是null来表示没有值的人。

相关问题

  • String.Empty和“”之间有什么区别?
  • 在表格列中表示无数据,使用null还是空字符串?

  • "The Sane"? 不可能是我认识的 Dana。 - vfilby
    @Joel,我很惊讶有多少人对Zim或G.I.R毫不了解。我也很惊讶我的一些朋友发现它令人厌恶。并不是说它是纯粹的好处,但其中有一些很棒的幽默点。 - vfilby
    我知道,但有时候假装不知道也很有趣。 - Dana the Sane
    1
    我在MVC表单集合或会话变量中经常遇到这个问题,我发现最有用的方法是使用??简写将null转换为String.Empty,然后应用所需的任何字符串操作。例如:(item ?? String.Empty).Trim().ToUpper() - sonjz
    4
    这不是建设性的吗? - nawfal
    17个回答

    116

    +1 是为了区分“空”和NULL。我同意“空”应该表示“有效但为空”,而“NULL”应该表示“无效”。

    因此,我会这样回答您的问题:

    当我需要一个有效的默认值时,可以更改或不更改,例如用户的中间名。

    NULL 当随后的代码未明确设置值时,它是一个错误。


    11
    当实际上两者有区别时,区分 NULL 和 empty 是很有用的。然而,在许多情况下,它们没有差别,因此拥有两种表示相同事物的方式是一种负担。 - Greg Smalter
    6
    @Greg:我同意多样性有可能会导致混乱,但它也可以是一个巨大的优势。使用简单、一致的惯例来区分有效和无效值——写“”或NULL,将使你的代码更容易理解。这就是为什么我总是用“if (var)”测试布尔值,“if (var != NULL)”测试指针,“if (var != 0)”测试整数——它们在编译器中都意味着相同的含义,但它们携带了额外的信息,有助于贫穷的开发人员维护我的代码。 - Adam Liss
    1
    @AdamLiss 针对Greg提到的用两种不同方式表示同一项负债的观点,您认为NULL或Empty代表了两个简单的条件:有效和无效。虽然我通常看到NULL表示用户尚未设置的属性。例如,用户资料中的字段。NULL可以表示用户尚未填写此特定信息,而IsEmpty则明确表示用户曾经填写过该信息,然后又回来删除了它。NULL可以表示一个属性或 - 8protons
    对象从未存在,或者尚不存在,这可能是完全有效的情况。 - 8protons

    32

    根据MSDN的说明:

    使用Empty值初始化字符串而不是null,可以减少NullReferenceException发生的机率。

    然而,始终使用IsNullOrEmpty()是一个好习惯。


    48
    仅仅因为你降低了异常发生的概率,并不意味着异常不应该发生。如果你的代码依赖于某个值的存在,它应该抛出一个异常! - rmeador
    1
    当然,没有异议。另一方面,如果你只是简单地将字符串连接起来...我认为这取决于编码风格、经验和情况。 - Tomalak
    主要是我用来区分该使用哪个的。 - PositiveGuy
    3
    别忘了在 .NET Framework 4+ 中使用 IsNullOrWhiteSpace() 函数。 - Paul C

    14

    你为什么想要初始化字符串呢?在声明变量时,你不必初始化变量,而且我认为只有当你分配的值在代码块的上下文中有效时,才应该这样做。

    我经常看到这种情况:

    string name = null; // or String.Empty
    if (condition)
    {
      name = "foo";
    }
    else
    {
      name = "bar";
    }
    
    return name;
    

    不将其初始化为null也同样有效。此外,大多数情况下您希望分配一个值。通过将其初始化为null,您可能会错过未分配值的代码路径。像这样:

    string name = null; // or String.Empty
    if (condition)
    {
      name = "foo";
    }
    else if (othercondition)
    {
      name = "bar";
    }
    
    return name; //returns null when condition and othercondition are false
    

    当您不将其初始化为null时,编译器会生成一个错误,指出并非所有代码路径都分配了值。当然,这只是一个非常简单的例子...

    Matthijs


    1
    在我认为几乎每个C#程序员都使用的Visual Studio中,您的第二种情况(没有= null)会生成一个警告,原因正如您所述 - 字符串的默认值是否为null并不重要。如果您不能保证通过每个代码路径进行分配,则IDE(和/或我想是底层编译器[?])将生成警告。虽然警告不会阻止编译,但它们仍然存在 - 留下那些容易解决的警告可以帮助掩盖可能需要程序员注意的其他警告。 - Code Jockey
    据我所知,第一种情况在不将name初始化为null的情况下(没有警告)也可以完美地运行,因为每个代码路径都会给name赋值 - 根本不需要在那里初始化。 - Code Jockey

    9

    对于大多数不是字符串处理软件的软件,程序逻辑不应依赖于字符串变量的内容。每当我在程序中看到这样的东西:

    if (s == "value")
    

    我有一种不好的感觉。为什么这个方法中有一个字符串文字?“s”是如何设置的?它是否知道逻辑取决于字符串的值?它是否知道必须小写才能工作?我应该通过更改为使用“String.Compare”来修复它吗?我应该创建一个“Enum”并解析它吗?
    从这个角度来看,代码哲学非常简单:尽可能避免检查字符串的内容。将字符串与“String.Empty”进行比较实际上只是将其与文字进行比较的特殊情况:除非确实需要,否则应避免执行此操作。
    知道了这一点,当我在我们的代码库中看到像这样的东西时,我并不惊讶:
    string msg = Validate(item);
    if (msg != null)
    {
       DisplayErrorMessage(msg);
       return;
    }
    

    我知道Validate永远不会返回String.Empty,因为我们写的代码比那更好。

    当然,世界其他地方并不是这样工作的。当你的程序处理用户输入、数据库、文件等时,你必须考虑其他的哲学观点。在这种情况下,你的代码的工作就是将混乱变得有序。其中一部分秩序就是知道空字符串应该表示String.Empty还是null

    (为了确保我没有胡说八道,我刚刚在我们的代码库中搜索了`String.IsNullOrEmpty'。所有54个实例都在处理用户输入、从Python脚本返回值、检查从外部API检索到的值等方法中。)


    6
    这实际上是C#语言中的一个漏洞。没有办法定义一个不能为null的字符串,这会引起问题。在很多情况下,NULL和String.Empty是相同的含义,但程序员不得不做出一个不必要的决定。这会导致其他程序员不得不处理NULL和String.Empty,非常烦人。
    更严重的问题是,数据库允许定义映射到C#字符串的字段,但数据库字段可以定义为NOT NULL。所以,在SQL Server中准确表示varchar(100) NOT NULL字段的方式无法使用C#类型表示。
    其他语言,如Spec #,允许这样做。
    我认为,C#无法定义一个不允许为null的字符串与其以前无法定义一个允许为null的int一样糟糕。
    回答你的问题:我始终使用空字符串进行默认初始化,因为它更类似于数据库数据类型。当NULL状态是多余的时候,我使用空字符串进行默认初始化,就像我将数据库列设置为NOT NULL一样。同样,我的许多DB列都设置为NOT NULL,所以当我将它们带入C#字符串时,该字符串将为空或有一个值,但永远不会为NULL。换句话说,我只有在null具有与String.Empty不同的含义并且发现这种情况比较少见时,才会将字符串初始化为NULL(但这里的人提供了合法的例子)。

    使用String.Empty仅类似于定义数据库字符串的一种方式。使用null来表示没有值更符合null nvarchar的要求。我认为任何有价值的DBA如果使用''来表示没有值,都会把你打得晕头转向。 - vfilby
    实际上,Greg,你的理解是错误的。非空值类型最不符合“数据库类型工作原理”,因为它们永远不能持有 null,因此永远不能映射到可空列。相反,任何字符串都可以映射到任何 varchar 列。 - Tor Haugen
    你说得对,我的最后一次断言不够清晰。大多数情况下,我的数据库列都是 NOT NULL(因为空字符串和 NULL 的含义没有区别),所以我尝试通过从不在字符串中存储 null 来保持它们的相似性,这就是我的意思。 - Greg Smalter

    5

    这要看情况。

    你需要确定该值是否缺失(有可能未定义)吗?

    空字符串对于该字符串的使用是否有效?

    如果您对两个问题都回答“是”,那么您应该使用 null。否则,您无法区分“没有值”和“空字符串”。

    如果您不需要知道是否没有值,那么空字符串可能更安全,因为它允许您在使用它时跳过 null 检查。


    4

    3

    我通常将其设置为""或null-使用String.IsNullOrEmpty进行检查,因此两者都可以。

    但是内心中的极客告诉我,在我有适当值之前应将其设置为null...


    3

    我总是使用string.empty来声明字符串;


    2

    这是一种错误避免技巧吗(是否可取)?因为 "" 仍然是一个字符串,您可以在其上调用字符串函数,如果它为 NULL,则会导致异常。


    1
    这是我通常听到的借口,听起来就像是懒惰。在我看来,“我不想麻烦检查这个值,所以我要走捷径”就是这样的。 - vfilby
    是的,我不反对。在某些情况下,减少错误检查代码的数量可能很好,但没有效果的函数调用也不是最好的选择。 - Dana the Sane

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接