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

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

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

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

片段1

 Foo fooInstance = new Foo(); 

片段2

 Foo fooInstance; 

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

我们必须区分三种情况,(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 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 )还是值类型( structenum )。 引用类型的默认值default(Foo)null ,即不引用任何内容的引用。 默认值default(Foo)或值类型是所有字段都具有默认值的类型的“实例”。 对于值类型(struct和enum), 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个参数的构造函数,并且该构造函数是可访问的时,才允许使用表达式new Foo()

在(1)中,我们忽略了愚蠢的情况,其中Foo是没有实例字段的结构。

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

 Foo* fooInstance; 

您的第一和第二个片段根本不相同。

Foo类型的Second Creates对象在memeroy中指向null。 First使用默认构造函数指向新对象。

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

如果你使用

 Foo fooInstance; 

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

代码片段2只是声明引用。 您还没有实例化该对象。 如果您尝试访问Snippet 2中的引用,则会收到编译器错误,指出该值尚未初始化。 这与C ++不同,其中Snippet 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初始化的,但实际上实际上是在堆栈上创建的。