【问题标题】:What is the difference between declaring a class null and instantiating a class?声明一个类为 null 和实例化一个类有什么区别?
【发布时间】:2016-11-12 23:45:52
【问题描述】:

我不确定我的问题是否有意义。但是我只是想知道这两行代码之间是否有区别:

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();

Dictionary<int, List<string>> myDictionary = null;

我知道第一行实例化了一个新的字典对象,但由于我没有在字典中添加任何内容,所以它只是一个空对象。第二行只是一个空字典对象。有区别吗?

【问题讨论】:

  • 你可以用你的调试器自己找出来?!?
  • Null 指向没有对象。在这里,我们看到了一些关于 null 文字(“null”)的信息和事实。 Null 由值 0 表示,但您不能在程序中使用 0 代替 null。 Null 会导致很多异常。
  • 尝试同时拨打.Count - 你很快就会看到不同之处!
  • 感谢所有非喷子的回复。 Downvoters,得到一个 lyfe pl0x。

标签: c# dictionary null instantiation


【解决方案1】:

第一种情况:

     Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
     myDictionary.Add(key,value); // NOT throw null reference exception.

第二种情况:

     Dictionary<int, List<string>> myDictionary = null;
     myDictionary.Add(key,value); // will throw null reference exception.

要使用任何集合对象,您需要先创建占位符。

【讨论】:

  • 我建议您将示例更改为可以编译的示例 - 并使用 C# 术语而不是 Java 术语(空 reference 异常,而不是空 pointer例外)
【解决方案2】:

可以这样想:

变量是一张空纸。您可能可能不会在其上写下可将您带到某个位置的地址。

第一行在纸上写下对象的地址(在 new 关键字之后创建)。

在第二行中,您只有一张空纸,预计(编译器)会在某些时候保存字典引用,但目前它只是一张空纸。因此,如果您尝试使用它转到字典地址,则不能(又名 NullReferenceException)。没有关于对象在哪里的信息(实际上没有地址)。

在代码中:

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
myDictionary.Add(1, "1"); // OK, myDictionary points to an address of
                         // Dictionary object and I can access it.

同时:

Dictionary<int, List<string>> myDictionary = null;
myDictionary.Add(1, "1");  // Fails at run-time, I have no address for a Dictionary object 
                           // here AKA : NullReferenceException

你说错了:

您并没有像您说的那样声明一个类为 null,您正在创建一个指向 null 的变量。

第二行不是你说的空字典对象。它是一个 Dictionary 类型的变量,指向 NULL。内存中没有空字典对象。

【讨论】:

    【解决方案3】:

    第一行实际上创建了一个对象(分配了内存);这意味着您有一些东西可以参考和采取行动(例如,myDictionary.Count() 将返回 0)。代码if (null == myDictionary) 将评估为false

    第二行不创建对象;您没有引用任何内容(在这种情况下,调用 myDictionary.Count() 将导致抛出 NullReferenceException)。代码if (null == myDictionary) 将评估为true

    【讨论】:

    • 不是你会在 C# 中使用Yoda Conditions,通常...
    • @Jon 旧习难改:)
    【解决方案4】:

    第二行不是空字典对象。尝试将内容添加到第二个字典对象以找出自己。通常,当您稍后在程序中真正想将一个对象分配给该引用时,您会指向一个对 null 的引用。

    【讨论】:

      【解决方案5】:

      简单的答案,第一种情况你可以使用它,第二种情况会给你NullReferenceException,而你继续这样做,因为 null 意味着不存在所以你不能访问它,直到它被实例化。

      第二个声明没有错,但是如果你想使用这意味着你需要实例化它们(在使用之前),否则它会抛出NullReferenceException。假设PopulateDictonary() 将是一个返回Dictionary 对象的方法,那么您可以使用此方法来实例化myDictionary

      即:

      Dictionary<int, List<string>> myDictionary;
      // Some code here, Not using myDictionary
      myDictionary = PopulateDictonary();
      

      注意:- 如果您有条件地实例化对象以避免异常,则应在使用 myDictionary 之前检查 Null。

      【讨论】:

      • 它叫NullReferenceException
      • 我也打算这样写。我可以在这个答案中添加你正在实例化的第一个,而在第二个中你只是声明它。要使用它,您必须实例化,而不仅仅是声明。
      • 这并不能真正清楚地解释差异。也许稍后会为该变量分配一个不同的值......也许它会被分配一个值有条件地......并且使用null 引用可能没问题。例如,它可以作为参数传递给另一个可以处理null 参数值的方法。 NullReferenceException 只会在代码尝试取消引用该值时抛出。
      • @JonSkeet:让我解释一下
      • 我会删除任何关于默认值的内容——如果这是一个局部变量声明,那就无关紧要了。同样,该变量可以“使用”将值传递给其他东西,同时仍然具有空值。
      【解决方案6】:

      这两个语句有很多区别,最基本的一个:第一个是初始化,而后者只是一个声明。考虑以下代码:

      Base b = new Derived();
      

      走向

      Base b = null;
      

      在第一条语句中,您创建一个新的Derived 实例并将其分配b。通常你需要一个类的实例来调用它的成员(为简单起见,我们在这里省略了静态成员),在你的例子中,Add-方法在Dictionary 中定义。通过声明,您只需定义可以在类的实例上调用的成员,但是对于调用这些成员的那个实例没有任何说明。因此,基本上您需要两个信息:由您使用的接口(不是 OOP 含义)定义的代码合同 - 在您的情况下,这只是 Dictionary&lt;int, List&lt;string&gt;&gt;。现在你知道什么你可以用这个类的一个实例来做。但是,只要您使用null-assignement,您就没有该类的实例。这是第二个信息——实际实例。

      在我之前的示例中,编译器应该如何知道您实际使用哪个类 - BaseDerived。这不一定会影响 what 您可以对实例执行的操作(由 Base 中的定义给出),而且您可以像 Derived 一样如何执行此操作在Base 中定义的做事有自己的逻辑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-22
        相关资源
        最近更新 更多