来自C ++,我对在C#中使用new
关键字感到困惑。
我理解它不像C ++的new
那样工作,因为你不必手动控制对象的生命周期,因为C#有垃圾收集。
但是,当阅读其他人的C#代码时,我会注意到代码片段1中的语句。完全避免使用new
会不会更容易,例如在代码片段2中?
Snippet 1
Foo fooInstance = new Foo();
Snippet 2
Foo fooInstance;
我的问题是,代码段1和代码段2之间有什么区别,为什么我更喜欢一个呢?
答案 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
)。引用类型的默认值enum
是default(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
初始化的,但实际上实际上是在堆栈上创建的。