【问题标题】:What is the difference between assigning null to an instance of a class and just declaration将 null 分配给类的实例和仅声明之间有什么区别
【发布时间】:2017-01-27 16:13:00
【问题描述】:

我试图了解将 null 分配给类的实例与仅声明该类之间是否有任何区别。

例如,我有一个类:

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

我声明了该类的两个实例:

MyClass Instance1 = null;
MyClass Instance2;  // just declaration

Instance1Instance2 有什么区别吗?

如果是,它安全吗?使用 'delcaration only' 样式是否是一个好习惯(就像上面示例中的 Instance2 一样)?

【问题讨论】:

  • 前者是一个用null初始化的变量,后者是一个没有显式初始化的变量,所以默认值也为null。区别在于:可读性,大家都知道 null 是期望的和期望的。如果你有一个out 参数,编译器会强制你分配一些东西,即使它是null
  • 例如,Resharper 会建议在这种情况下删除 null 分配。
  • 是的,有区别。在第二种情况下,如果该值是一个字段,它将自动分配默认值,但如果它是一个局部变量,则不会。如果然后被代码“读取”,这会导致编译器错误“使用未分配的局部变量”
  • 很多时候我只在某人的代码中看到了一个实例的声明。试图了解这样做是否正确。感谢 cmets 伙计们。
  • 感谢大家的回答。你所有的答案都有很大帮助。

标签: c# null declaration


【解决方案1】:

然后我正在创建该类的两个实例:

您没有创建任何实例。如果曾经创建过实例,您将创建两个放置实例的位置。您明确表示的第一个没有实例,第二个只是没有实例。

Instance1Instance2 有什么区别吗?

这取决于你在哪里做的。

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

如果您在方法中包含该代码(包括构造函数或属性访问器),那么您就有两个局部变量(尽管惯例是在这里使用小写字母)。

第一个已设置为 null,您可以使用它执行对 null 有效的操作(将其传递给方法 [尽管它可能如果它拒绝接受 null 则抛出异常) 将其与某事物进行比较,以确认它确实为 null 或确实与确实有实例的事物不同。

第二个没有被赋值,因此除了给它赋值(无论是 null 还是实例)之外,做任何事情都是非法的。在确定设置之前任何尝试做任何事情都将是编译器错误。例如:

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 以开始这样的错误不会那么明显,并且可能导致错误。

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

但话虽如此,在可能的情况下总是最好避免使用复杂的逻辑,因此这种复杂的链应该很少见。在其他情况下,在同一点声明和分配的风格意味着您在两者之间没有可能出现错误的间隙。

【讨论】:

  • 感谢您的回答,现在我明白何时以及为什么要使用 MyClasss 实例了;
【解决方案2】:

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

给你明确分配null的第一个。到第二个你没有分配任何东西。因此它包含默认值,即引用类型的null1

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

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

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

【讨论】:

  • 在局部变量的情况下,未初始化的变量实际上是否包含 null 是否重要?编译器不会让您访问未初始化的本地,那么它包含的内容真的很重要吗?
  • @Kyle 对,在看到 stuartd 的评论后,我不太确定局部变量是否已初始化……可能不会,否则编译器为什么会抛出该错误……只是想得到编辑我的答案的措辞权。
  • @RenéVogt 看看 Jon Hanna 的回答。他有一个很好的解释。顺便说一句,谢谢你的回答。
【解决方案3】:

null 关键字是表示null 引用的文字,它不引用任何对象。 nullreference-type 变量的默认值。普通值类型不能为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;
       }

【讨论】:

    【解决方案4】:

    它们是一样的。

    其实如果你用的是ReSharper,它会告诉你“= null”是多余的。

    至于你的第二个问题。我不会在没有立即分配的情况下声明很多变量。

    所以如果你只是像这样声明它

    MyClass Instance2;
    

    然后设置它。

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

    所有这些都可以组合在一个语句中

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

    【讨论】:

    • 这根本不能回答问题。
    • @InBetween 你怎么看?第一个问题。他们是一样的。第二个问题是只声明变量好。不,在大多数情况下你想初始化它们。
    • OP 询问MyClass instance1MyClass instance2 = null 之间的区别。前者是未初始化的变量,后者是初始化为null的变量,就编译器而言,这是两个截然不同的东西。
    猜你喜欢
    • 1970-01-01
    • 2014-02-26
    • 2016-11-12
    • 2014-01-26
    • 2019-08-09
    • 2011-01-26
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    相关资源
    最近更新 更多