Are there any differences between the following two ways of field initialization? When to u开发者_StackOverflowse which one?
First way
public class Class1
{
private SomeClass someclass;
public Class1()
{
someclass = new SomeClass(some arg);
}
}
Second way
public class Class1
{
private SomeClass someclass = new SomeClass(some arg);
}
The field in the second example could be readonly.
You cannot make use of the this
keyword when initializing fields inline. The reason for this is the order in which the code is executed: for all intents and purposes, the code to initialize a field inline is run before the constructor for the class (i.e. the C# compiler will prevent access to the this
keyword). Basically what that means is this will not compile:
public class Class1
{
private SomeClass someclass = new SomeClass(this);
public Class1()
{
}
}
but this will:
public class Class1
{
private SomeClass someclass;
public Class1()
{
someclass = new SomeClass(this);
}
}
It's a subtle difference, but one worth making a note of.
The other differences between the two versions are only really noticeable when using inheritance. If you have two classes which inherit from each other, the fields in the derived class will be initialized first, then the fields in the base class will be initialized, then the constructor for the base class will be invoked, and finally, the constructor for the derived class will be invoked. There are some cases where you need to be very careful with this, as it could cause a fruit salad of complications if you don't realise what is going on (one of which involves calling a virtual method inside the base class constructor, but that is almost never a wise move). Heres an example:
class BaseClass
{
private readonly object objectA = new object(); // Second
private readonly object objectB;
public BaseClass()
{
this.objectB = new object(); // Third
}
}
class DerivedClass : BaseClass
{
private object objectC = new object(); // First
private object objectD;
public DerivedClass()
{
this.objectD = new object(); // Forth
}
}
You will need to set breakpoints on all of the lines that initialize fields to be able to see the correct sequence.
There is a subtle difference, in that the field in the second example will be initialised before fields in the base class are initialised, and the field in the first example will be initialised after. This very rarely has any impact, however.
Largely it's a matter of style and preference. Personally I prefer the second, as it leaves the constructor clear for more logic based initialisation, but there is a strong case to make for having all initialisation done in the constructor.
Just for completeness, the order of initialisation goes:
- Static fields
- Static constructor
- Instance fields
- Base static fields
- Base static constructor
- Base instance fields
- Base constructor
- Constructor
Apart from the number of lines of code, there are subtle differences.
Field initializations happen before constructors are run, for example. Doesn't make much of a difference in your example, but is something to keep in mind.
I would keep field initialsizations as in your second example to simple ones (strings or integers), to avoid possible exceptions occuring during initialization.
And as mentioned, in both ways the field can be readonly, as readonly fields can only be written to during construction.
In fact the fields in both those classes could be readonly.
There are differences.
Imagine you have a class with multiple constructors. Using the first way, each constructor would be required to create these objects. This may be intended behaviour, as you may want the object to be created differently each time. This extra responsibility on the contructor may be a bad thing, because if you don't remember to initialise the variable in each constructor you are going to end up with a null object.
There is a tiny amount of efficiency to consider but it is hardly significant - the first way requires two assignments, firstly to null and then the created object, while in the second way the object created and initialised all in one step.
Then think about static variables. Static variables MUST be declared the second way, because there is never any guarantee that instances of your class will be created.
The constructor way is recommended, because of exceptions management and debug commodity.
If a field should be readonly, you can declare a readonly property (this it with getter only).
The instance field variable initializers of a class correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors of that class. The variable initializers are executed in the textual order in which they appear in the class declaration.
A variable initializer for an instance field cannot reference the instance being created. Thus, it is a compile-time error to reference this in a variable initializer, as it is a compile-time error for a variable initializer to reference any instance member through a simple-name.
The default value initialization occurs for all fields, including fields that have variable initializers. Thus, when a class is initialized, all static fields in that class are first initialized to their default values, and then the static field initializers are executed in textual order. Likewise, when an instance of a class is created, all instance fields in that instance are first initialized to their default values, and then the instance field initializers are executed in textual order.
The first one is useful if your "some arg" argument isn't static. If that arguments is only available through the constructor then this is the way to take. The second way comes with a problem. If an Exception gets thrown during instanciation of SomeClass there's no way of catching that Exception inside Class1.
Best wishes,
Fabian
There is very little difference. The compiler will place all of your inline initializers at the beginning of your constructor(s), in the order they were defined.
You might want to use the constructor approach if you need complex logic to initialize a field, otherwise I think the inline approach is more clear, and easier to maintain because the compiler handles calling it for you.
Actually I prefer second one for readability and easy of debugging, you can wrap the call by try catch, but in the first you can not.
精彩评论