问题
Coming from C++, I am confused as to the use of the new
keyword in C#.
I understand that it doesn't work like C++'s new
in the sense that you do not have to manually control the lifetime of the object, as C# has garbage collection.
However, when reading over other peoples C# code I notice statements like in code snippet 1. Wouldn't it be far easier to avoid the use of new
altogether, like in code snippet 2?
Snippet 1
Foo fooInstance = new Foo();
Snippet 2
Foo fooInstance;
My question is, what are the differences between snippet 1 and snippet 2, and why should I prefer one over the other?
回答1:
We must discriminate between three cases, (1) local variables, (2) (non-static) fields inside structs, and (3) fields inside classes.
For local variables, that is variables declared inside a method (or inside a constructor, or property/indexer/event accessor), the two are not equivalent:
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)
}
}
For instance fields (non-static fields) inside a struct
, only one of the "snippets" is allowed:
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
}
For fields inside a class (and static
fields of a struct), the situation depends on whether Foo
itself is a reference type (class
) or a value type (struct
or enum
). The default value default(Foo)
of a reference type is null
, the reference that does not refer anything. The default value default(Foo)
or a value type is the "instance" of the type where all fields have their default values. For value types (struct and enum), new Foo()
(no arguments) and default(Foo)
is the same thing. Therefore:
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)
}
It should be noted that if Foo
is a reference type, the expression new Foo()
is only allowed if the type actually has a constructor that takes 0 arguments, and if that constructor is accessible.
In (1) we disregarded the silly case where Foo
is a struct with no instance fields.
回答2:
Assuming Foo is a reference type like a class, the second code snippet basically just allocates a pointer. The equivalent C++ code would be
Foo* fooInstance;
Your snippets one and two are simply not equivalent.
回答3:
The Second Creates Object of type Foo points to null in memeroy. The First points to new object using default constructor.
If you use the second and say fooInstance.SomeProperty = something. This will throw an exception as fooInstance points to null.
回答4:
If you use
Foo fooInstance;
...in C#, you're just creating a reference variable on stack which points to nothing; no default constructor is called (like it would be in C++).
回答5:
Snippet 2 is simply declaring the reference. You haven't instantiated the object yet. If you tried to access the reference in Snippet 2 you would get a compiler error saying the value hasn't been initialized. This is different from C++ where Snippet 2 would declare a constructed object on the stack.
回答6:
The first snippet
Foo fooInstance = new Foo();
will, as has been said, create a new instance of Foo and place a reference to it in the variable fooInstance
.
For the second snippet
Foo fooInstance;
it depends on where it is placed:
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
}
}
Extra caution should be taken if Foo is not declared as class but as struct. Although it is also initialized using new
, the instance is actually created on the stack then.
来源:https://stackoverflow.com/questions/23034541/operator-new-in-c-sharp-vs-c