将null分配给类的实例和仅声明之间有什么区别

时间:2017-01-27 16:13:01

标签: c# null declaration

我试图理解将null分配给类的实例与仅声明此类之间是否存在任何区别。举个例子,我有一个班级:

//
// Define Start Underline and Stop Underline tokens
START_UNDERLINE : "SomeWordToken(s) possibly \uxxx values";
STOP_UNDERLINE  : "SomeOtherToken(s) possibly \uxxx values";

DIGITS : [0-9]+
UNDERLINED_DIGITS : START_UNDERLINE DIGITS STOP_UNDERLINE;

enter_underline  : START_UNDERLINE;
exit_underline   : STOP_UNDERLINE;

然后我创建了两个类的实例:

public class MyClass
{
    public string FirstProperty { get; set; }
    public int SecondProperty { get; set; }
}

MyClass Instance1 = null; MyClass Instance2; // just declaration Instance1之间有什么区别吗? 是的,是否安全,只有Instance2声明是一个好习惯?

4 个答案:

答案 0 :(得分:6)

  

然后我创建了两个类的实例:

您没有创建任何实例。如果创建实例,则创建两个放置实例的位置。你明确说过的第一个没有实例,第二个没有实例。

  

Instance1Instance2之间有什么区别吗?

这取决于你在哪里做到了。

如果该代码位于classstruct之内,那么您创建了两个字段,这两个字段最初都将设置为null,除非构造函数执行其他操作。< / p>

如果你在方法中包含那些代码(包括构造函数或属性访问器),那么你有两个局部变量(虽然惯例是在这里使用小写)。

第一个被设置为null,你可以用它做一些有效的null(把它传递给一个方法[虽然它可能如果拒绝接受null则会抛出异常)将它与某些东西进行比较,以确认它确实是空的,或者确实与真正具有实例的东西相同。

第二个尚未分配,因此除了分配某些内容(无论是null还是实例)之外,执行任何操作都是非法的。在确定设置之前做任何事情的任何尝试都将是编译器错误。 E.g:

MyClass Instance2;
if (valueThatJustHappensToAlwaysBeTrue)
{
   Instance2 = new MyClass();
}
bool isNull = Instance2 == null; // Error! Not guaranteed to be assigned strongly enough for the compiler to know.
  

是的,它是否安全,让Instance2只有声明是一个好习惯?

如果可能的话,尽可能接近第一个作业(初始化),理想情况下同时宣布这是一个好习惯:

MyClass instance = new MyClass();

但是,如果您有一些不同的可能路径,例如:

MyClass instance;
if (boolValue)
{
   instance = new MyClass(1); // Yes, I know there's no int-taking ctor on your class, but it defeats the argument when the bare constructor is the only one available, so let's say there is.
}
else if (otherBoolValue)
{
   throw new SomeException();
}
else if (someIntValue > 42)
{
   instance = new MyClass(3);
}
else
{
   instance = new MyClass(9);
}

现在,使用未初始化的instance无法到达此链的末尾。它将被设置,或者将抛出异常。如果我们认为从MyClass instance = null开始可能会“更安全”,那么我们可能会隐藏一个错误。上面的逻辑意味着为每个路径分配一些东西,并且由于规则不能使用不能保证分配的实例,那么错误会导致编译器错误,并且错误很明显。如果它被分配给一个“占位符”null,从这个错误开始就不会那么明显,并且可能会导致错误。

所以在像裸声明的情况下更好。

但是,尽管如此,在可能的情况下总是更好地避免使用复杂的逻辑,因此那些复杂的链条应该是罕见的。在其他情况下,在同一点上声明和分配的方式意味着你可以在两者之间没有差距,而错误可能会出现。

答案 1 :(得分:5)

在您的示例中,您没有创建任何实例。您声明了两个变量

首先明确分配 null。到第二个你不分配任何东西。因此它包含默认值,对于引用类型是null 1

从技术上讲,这两个变量的之间没有区别。但是如果您尝试使用Instance2的值,编译器可能会引发错误,因为编译器不允许使用未初始化的变量:

MyClass Instance1 = null;
MyClass Instance2;
Console.WriteLine(Instance1); // fine
Console.WriteLine(Instance2); // raises error CS0165

1 正如stuartd和Kyle评论的那样,编译器根本不会初始化局部变量,这解释了错误。在分配一个变量之前,不能依赖具有任何特定值的变量,无论是null还是已创建的MyClass实例。字段和属性初始化为类型的默认值(null用于引用类型。)

答案 2 :(得分:1)

null关键字是表示null引用的文字,不引用任何对象。 null引用类型变量的默认值。普通值类型不能是null

示例:

 class Program
    {
        class MyClass
        {
            public void MyMethod() { }
        }

        static void Main(string[] args)
        {
            // Set a breakpoint here to see that mc = null.
            // However, the compiler considers it "unassigned."
            // and generates a compiler error if you try to
            // use the variable.
            // try Console.WriteLine(mc);
            // it will return error CS0165: Use of unassigned local variable `mc'
            MyClass mc;

            // Now the variable can be used, but...
            mc = null;

            // ... a method call on a null object raises 
            // a run-time NullReferenceException.
            // Uncomment the following line to see for yourself.
            // mc.MyMethod();

            // Now mc has a value.
            mc = new MyClass();

            // You can call its method.
            mc.MyMethod();

            // Set mc to null again. The object it referenced
            // is no longer accessible and can now be garbage-collected.
            mc = null;
       }

答案 3 :(得分:-2)

他们是一样的。

事实上,如果您使用的是ReSharper,它会告诉您“= null”是多余的。

关于你的第二个问题。如果没有立即分配,我不会声明很多变量。

所以,如果你只是声明它

MyClass Instance2;

然后设置它。

MyClass = new Instance2;

Instance2.FirstProperty = "some string";
Instance2.SecondProperty = 1;

这可以全部合并为一个声明

var MyClass = new Instance2 { FirstProperty = "some string", SecondProperty = 1 };