C#vs C ++中的新操作符

时间:2014-04-12 18:41:19

标签: c# c++ new-operator

来自C ++,我对在C#中使用new关键字感到困惑。

我理解它不像C ++的new那样工作,因为你不必手动控制对象的生命周期,因为C#有垃圾收集。

但是,当阅读其他人的C#代码时,我会注意到代码片段1中的语句。完全避免使用new会不会更容易,例如在代码片段2中?

Snippet 1

Foo fooInstance = new Foo();

Snippet 2

Foo fooInstance;

我的问题是,代码段1和代码段2之间有什么区别,为什么我更喜欢一个呢?

6 个答案:

答案 0 :(得分:8)

假设Foo是类的引用类型,第二个代码片段基本上只分配一个指针。等效的C ++代码是

Foo* fooInstance;

你的一两个片段根本不相同。

答案 1 :(得分:3)

我们必须区分三种情况,(1)局部变量,(2)(结构体内的非静态)字段,以及(3)类内的字段。


对于局部变量,即在方法内部(或构造函数或属性/索引器/事件访问器内)声明的变量,两者不等效:

class C
{
  void M()
  {
    Foo fooInstance = new Foo();
    // the variable is "definitely assigned" and can be read (copied, passed etc)
    // consider using the 'var' keyword above!
  }
}

class C
{
  void M()
  {
    Foo fooInstance;
    // the variable is not "definitely assigned", you cannot acquire its value
    // it needs to be assigned later (or can be used as 'out' parameter)
  }
}

例如struct内的字段(非静态字段),只允许其中一个“片段”:

struct S
{
  Foo fooInstance = new Foo(); // compile-time error! cannot initialize here
}

struct S
{
  Foo fooInstance; // OK, access level is 'private' when nothing is specified
}

对于类(和结构的static字段)内的字段,情况取决于Foo本身是引用类型(class)还是值类型({{ 1}}或struct)。引用类型的默认值enumdefault(Foo),该引用不引用任何内容。默认值null或值类型是所有字段都具有默认值的类型的“实例”。对于值类型(struct和enum),default(Foo)(无参数)和new Foo()是相同的。因此:

default(Foo)

应该注意的是,如果class C { Foo fooInstance = new Foo(); // OK, private } class C { Foo fooInstance; // OK, private // equivalent to 'Foo fooInstance = null;' if 'Foo' is a reference type (class, interface, delegate, array) // equivalent to 'Foo fooInstance = new Foo();' is 'Foo' is a value type (struct, enum) } 是引用类型,则表达式Foo仅在类型实际具有带0参数的构造函数时才允许,并且该构造函数是可访问的。

在(1)中,我们忽略了new Foo()是一个没有实例字段的结构的愚蠢案例。

答案 2 :(得分:2)

第二个创建Foo类型的对象在memeroy中指向null。 First使用默认构造函数指向新对象。

如果你使用第二个并说fooInstance.SomeProperty =某事。当fooInstance指向null时,这将抛出异常。

答案 3 :(得分:2)

Snippet 2只是声明引用。您尚未实例化该对象。如果您尝试访问Snippet 2中的引用,则会收到编译器错误,指出该值尚未初始化。这与C ++不同,其中Snippet 2将在堆栈上声明构造对象。

答案 4 :(得分:2)

如果您使用

Foo fooInstance;

...在C#中,你只是在堆栈上创建一个指向什么都没有的引用变量;没有调用默认构造函数(就像在C ++中一样)。

答案 5 :(得分:2)

第一个片段

Foo fooInstance = new Foo();
如上所述,

将创建一个新的Foo实例,并在变量fooInstance中对它进行引用。

对于第二个片段

 Foo fooInstance; 

取决于它的放置位置:

 public class MyClass
 {
     Foo m_foo = null; // member, the "= null" part is redundant and not needed
     Foo m_foo = new Foo(); // member, initialized as part of the constructor call
     void Bar()
     {
          Foo f; // Local variable
          f.MyMethod(); // Compile time error: f is not initialized
          Foo f2=null;
          f2.MyMethod(); // Runtime error: Nullreference exception
     }
 }

如果Foo未声明为类而是声明为struct,则应格外小心。虽然它也是使用new初始化的,但实际上实际上是在堆栈上创建的。