465

I've been programming in C# and Java recently and I am curious where the best place is to initialize my class fields.

Should I do it at declaration?:

public class Dice
{
    private int topFace = 1;
    private Random myRand = new Random();

    public void Roll()
    {
       // ......
    }
}

or in a constructor?:

public class Dice
{
    private int topFace;
    private Random myRand;

    public Dice()
    {
        topFace = 1;
        myRand = new Random();
    }

    public void Roll()
    {
        // .....
    }
}

I'm really curious what some of you veterans think is the best practice. I want to be consistent and stick to one approach.

Mihir
  • 95
  • 2
  • 11
mmcdole
  • 91,488
  • 60
  • 186
  • 222
  • 3
    Note that for structs you cannot have instance field initializers, so you have no choice but to use the constructor. – yoyo Jul 10 '14 at 23:45
  • Since you brought up "best practice": https://www.satisfice.com/blog/archives/5164, https://www.forbes.com/sites/mikemyatt/2012/08/15/best-practices-arent/#67d25efc407b – Stephen C Feb 21 '20 at 02:27

16 Answers16

344

My rules:

  1. Don't initialize with the default values in declaration (null, false, 0, 0.0…).
  2. Prefer initialization in declaration if you don't have a constructor parameter that changes the value of the field.
  3. If the value of the field changes because of a constructor parameter put the initialization in the constructors.
  4. Be consistent in your practice (the most important rule).
poke
  • 369,085
  • 72
  • 557
  • 602
kokos
  • 43,096
  • 5
  • 36
  • 32
  • I don't really understand 1. Do you mean the default value of the type, or the value you want as default. Say I declare an int which default should be 5 I shouldn't do it in declaration, but in the constructor? – Didier A. Sep 11 '12 at 19:54
  • 4
    I expect that kokos means that you should not initialize members to their default values (0, false, null etc.), since the compiler will do that for you (1.). But if you want to initialize a field to anything other than its default value, you should do it in the declaration (2.). I think that it might be the usage of the word "default" that confuses you. – Ricky Helgesson Oct 11 '12 at 17:12
  • 102
    I disagree with rule 1 - by not specifying a default value (regardless of whether it's initialised by the compiler or not) you are leaving the developer to *guess* or go looking for the documentation on what the default value for that particular language would be. For readability purposes, I would always specify the default value. – James Jan 09 '13 at 12:50
  • 35
    The default value of a type `default(T)` is always the value that has an internal binary representation of `0`. – Olivier Jacot-Descombes Mar 13 '13 at 19:26
  • 1
    I like to initialize the values in the declaration only when all contructors would otherwise result in that same value when they exit anyway, otherwise I have the contructor do the initialization. And I would initialize with default values if that is the "default" the class is expecting. The compiler *should* optimize the initialization anyway. – Cemafor Apr 26 '13 at 18:54
  • 3
    Explicit initialization with a default value would suggest to me that the value is likely to be read before anything else writes it; I would thus consider such declarations helpful in cases where the implication is true. – supercat Jul 02 '14 at 20:42
  • 15
    Whether or not you like rule 1, it can't be used with readonly fields, which *must* be explicitly initialized by the time the constructor is finished. – yoyo Jul 10 '14 at 23:39
  • I want to initialize a field and take a value from Castle, I should do it in the declaration or constructor or in castle configuration file? – user1785960 May 30 '16 at 08:31
  • @kokos According to your rule 1, do we need to initialize default values in the constructor instead at the declaration or is it really needed to initialize them to default values since they are instance variables – Kasun Siyambalapitiya Jul 21 '16 at 06:57
  • I disagree with rule 1 as well. As code is meant for humans to read and only incidentally for computers to execute, I like to initialize references explicitly as it communicates that I intended to do so explicitly, rather than just lazily leaving it "uninitialized", which actually initializes it to the default value. – Patrick Szalapski Oct 18 '16 at 16:55
  • 48
    I disagree with those who disagree with rule 1. It's OK to expect others to learn the C# language. Just as we don't comment each `foreach` loop with "this repeats the following for all items in the list", we don't need to constantly restate C#'s default values. We also don't need to pretend that C# has uninitialized semantics. Since the absence of a value has a clear meaning, it's fine to leave it out. If it's ideal to be explicit, you should always use `new` when creating new delegates (as was required in C# 1). But who does that? The language is designed for conscientious coders. – Edward Brey May 14 '17 at 05:24
  • 1
    @James, You would need a team standard that said the default values are to be initialized at field declaration but then everyone would learn them anyway(after so many repetitions), so then your reason would become invalid. I think a developer should know what default values are and if he/she doesn't then it isn't difficult to learn them. I respectfully disagree with you – IEnjoyEatingVegetables Oct 29 '17 at 02:14
  • 1
    @EdwardBrey Yes, I agree and wished I had read yours before writing mine. – IEnjoyEatingVegetables Oct 29 '17 at 02:15
  • 1
    @JohnOsborne explicitness shows intent, I prefer to read code that clearly shows what the program should do rather than having to remember how a compiler works each time. Also, for however unlikely it is, compiler behaviour can change, I'd rather not risk a breaking change for syntactic sugar. Other compilers flag uninitialised variables as errors (or warnings) for that reason, compilers aren't smart, they just abide by rules and prefer us to tell them what they ought to be doing. – James Oct 30 '17 at 08:25
  • @PatrickSzalapski I disagree with that. Computer code is literally just instructions for a computer, so in no sense is it "incidental" that ***computers*** execute ***computer*** code. Computer code serves as an interface between the developer and the computer, and so priority of readability and performance is subjective. I'd very much argue that a good, experienced developer would learn the language, however, and not need to use "readability" as a crutch when programming, *especially* when doing so sacrifices performance; I want my computer to perform the tasks I tell it to well. – Kröw Jun 25 '19 at 10:21
  • 1
    @EdwardBrey That's a good point, but I personally think a `foreach` without a comment is still readable/clear while an "uninitialised" variable isn't - I don't need to check the C# docs to remember how a `foreach` loop works, but I would need to check the docs to remember what a type's default values are. – Ruben9922 Oct 24 '19 at 11:33
  • 1
    @Ruben9922 It won’t take many trips to the docs for the all-bits-zero rule to feel as second nature as `foreach`. – Edward Brey Oct 24 '19 at 11:45
153

In C# it doesn't matter. The two code samples you give are utterly equivalent. In the first example the C# compiler (or is it the CLR?) will construct an empty constructor and initialise the variables as if they were in the constructor (there's a slight nuance to this that Jon Skeet explains in the comments below). If there is already a constructor then any initialisation "above" will be moved into the top of it.

In terms of best practice the former is less error prone than the latter as someone could easily add another constructor and forget to chain it.

Quibblesome
  • 25,225
  • 10
  • 61
  • 100
  • 7
    That is not correct if you choose to initialize the class with GetUninitializedObject. Whatever is in the ctor will not be touched but the field declarations will be run. – Wolf5 Jan 03 '13 at 09:18
  • 34
    Actually it does matter. If the base class constructor calls a virtual method (which is generally a bad idea, but can happen) which is overridden in the derived class, then using instance variable initializers the variable will be initialized when the method is called - whereas using initialization in the constructor, they won't be. (Instance variable initializers are executed *before* the base class constructor is called.) – Jon Skeet Aug 13 '13 at 08:52
  • 2
    Really? I swear I grabbed this info from Richter's CLR via C# (2nd edition I think) and the gist of it was that this was syntactic sugar (I may have read it wrong?) and the CLR just jammed the variables into the constructor. But you're stating that this isn't the case, i.e. the member initialisation can fire before ctor initialisation in the crazed scenario of calling a virtual in base ctor and having an override in the class in question. Did I understand correctly? Did you just find this out? Puzzled as to this up-to-date comment on a 5 year old post (OMG has it been 5 years?). – Quibblesome Aug 13 '13 at 19:18
  • @Quibblesome: A child class constructor will contain a chained call to the parent constructor. A language compiler is free to include as much or as little code before that as it likes, provided that the parent constructor is called exactly once on all code paths, and limited use is made of the object under construction prior to that call. One of my annoyances with C# is that while it can generate code which initializes fields, and code which uses constructor parameters, it offers no mechanism for initializing fields based upon constructor parameters. – supercat Feb 20 '15 at 21:02
  • 1
    @Quibblesome, former one will be an issue, if the value is assigned and passed to a WCF method. Which will reset the data to default data type of the model. The best practice is to do the initialisation in constructor(later one). – Pranesh Janarthanan Dec 23 '19 at 15:50
17

I think there is one caveat. I once committed such an error: Inside of a derived class, I tried to "initialize at declaration" the fields inherited from an abstract base class. The result was that there existed two sets of fields, one is "base" and another is the newly declared ones, and it cost me quite some time to debug.

The lesson: to initialize inherited fields, you'd do it inside of the constructor.

xji
  • 7,341
  • 4
  • 40
  • 61
  • So if you refer the field by `derivedObject.InheritedField`, is it referring to your base one or the derived one? – RayLuo May 03 '17 at 23:39
  • 1
    @RayLuo For this kind of situation, look at the compiler warnings. There would be a warning like: *CS0108 "MyProperty hides inherited member MyProperty. Use the new keyword if hiding was intended."* – JohnB Jul 23 '22 at 17:44
16

The semantics of C# differs slightly from Java here. In C# assignment in declaration is performed before calling the superclass constructor. In Java it is done immediately after which allows 'this' to be used (particularly useful for anonymous inner classes), and means that the semantics of the two forms really do match.

If you can, make the fields final.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
7

Assuming the type in your example, definitely prefer to initialize fields in the constructor. The exceptional cases are:

  • Fields in static classes/methods
  • Fields typed as static/final/et al

I always think of the field listing at the top of a class as the table of contents (what is contained herein, not how it is used), and the constructor as the introduction. Methods of course are chapters.

Noel
  • 2,061
  • 4
  • 31
  • 47
  • 2
    Why is it "definitely" so? You provided only a style preference, without explaning its reasoning. Oh wait, never mind, according to @quibblesome 's [answer](http://stackoverflow.com/a/25130/728675), they are "utterly equivalent", so it is really just a personal style preference. – RayLuo May 03 '17 at 23:45
7

In Java, an initializer with the declaration means the field is always initialized the same way, regardless of which constructor is used (if you have more than one) or the parameters of your constructors (if they have arguments), although a constructor might subsequently change the value (if it is not final). So using an initializer with a declaration suggests to a reader that the initialized value is the value that the field has in all cases, regardless of which constructor is used and regardless of the parameters passed to any constructor. Therefore use an initializer with the declaration only if, and always if, the value for all constructed objects is the same.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
6

There are many and various situations.

I just need an empty list

The situation is clear. I just need to prepare my list and prevent an exception from being thrown when someone adds an item to the list.

public class CsvFile
{
    private List<CsvRow> lines = new List<CsvRow>();

    public CsvFile()
    {
    }
}

I know the values

I exactly know what values I want to have by default or I need to use some other logic.

public class AdminTeam
{
    private List<string> usernames;

    public AdminTeam()
    {
         usernames = new List<string>() {"usernameA", "usernameB"};
    }
}

or

public class AdminTeam
{
    private List<string> usernames;

    public AdminTeam()
    {
         usernames = GetDefaultUsers(2);
    }
}

Empty list with possible values

Sometimes I expect an empty list by default with a possibility of adding values through another constructor.

public class AdminTeam
{
    private List<string> usernames = new List<string>();

    public AdminTeam()
    {
    }

    public AdminTeam(List<string> admins)
    {
         admins.ForEach(x => usernames.Add(x));
    }
}
Robert Columbia
  • 6,313
  • 15
  • 32
  • 40
Miroslav Holec
  • 3,139
  • 25
  • 22
4

What if I told you, it depends?

I in general initialize everything and do it in a consistent way. Yes it's overly explicit but it's also a little easier to maintain.

If we are worried about performance, well then I initialize only what has to be done and place it in the areas it gives the most bang for the buck.

In a real time system, I question if I even need the variable or constant at all.

And in C++ I often do next to no initialization in either place and move it into an Init() function. Why? Well, in C++ if you're initializing something that can throw an exception during object construction you open yourself to memory leaks.

almic
  • 17
  • 6
Dan Blair
  • 2,399
  • 3
  • 21
  • 32
3

The design of C# suggests that inline initialization is preferred, or it wouldn't be in the language. Any time you can avoid a cross-reference between different places in the code, you're generally better off.

There is also the matter of consistency with static field initialization, which needs to be inline for best performance. The Framework Design Guidelines for Constructor Design say this:

✓ CONSIDER initializing static fields inline rather than explicitly using static constructors, because the runtime is able to optimize the performance of types that don’t have an explicitly defined static constructor.

"Consider" in this context means to do so unless there's a good reason not to. In the case of static initializer fields, a good reason would be if initialization is too complex to be coded inline.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
2

Being consistent is important, but this is the question to ask yourself: "Do I have a constructor for anything else?"

Typically, I am creating models for data transfers that the class itself does nothing except work as housing for variables.

In these scenarios, I usually don't have any methods or constructors. It would feel silly to me to create a constructor for the exclusive purpose of initializing my lists, especially since I can initialize them in-line with the declaration.

So as many others have said, it depends on your usage. Keep it simple, and don't make anything extra that you don't have to.

MeanJerry
  • 79
  • 6
2

Consider the situation where you have more than one constructor. Will the initialization be different for the different constructors? If they will be the same, then why repeat for each constructor? This is in line with kokos statement, but may not be related to parameters. Let's say, for example, you want to keep a flag which shows how the object was created. Then that flag would be initialized differently for different constructors regardless of the constructor parameters. On the other hand, if you repeat the same initialization for each constructor you leave the possibility that you (unintentionally) change the initialization parameter in some of the constructors but not in others. So, the basic concept here is that common code should have a common location and not be potentially repeated in different locations. So I would say always put it in the declaration until you have a specific situation where that no longer works for you.

1

There is a slight performance benefit to setting the value in the declaration. If you set it in the constructor it is actually being set twice (first to the default value, then reset in the ctor).

John Meagher
  • 22,808
  • 14
  • 54
  • 57
1

When you don't need some logic or error handling:

  • Initialize class fields at declaration

When you need some logic or error handling:

  • Initialize class fields in constructor

This works well when the initialization value is available and the initialization can be put on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate. Instance variables can be initialized in constructors, where error handling or other logic can be used.

From https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html .

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
0

I normally try the constructor to do nothing but getting the dependencies and initializing the related instance members with them. This will make you life easier if you want to unit test your classes.

If the value you are going to assign to an instance variable does not get influenced by any of the parameters you are going to pass to you constructor then assign it at declaration time.

Iker Jimenez
  • 7,105
  • 9
  • 49
  • 46
0

Not a direct answer to your question about the best practice but an important and related refresher point is that in the case of a generic class definition, either leave it on compiler to initialize with default values or we have to use a special method to initialize fields to their default values (if that is absolute necessary for code readability).

class MyGeneric<T>
{
    T data;
    //T data = ""; // <-- ERROR
    //T data = 0; // <-- ERROR
    //T data = null; // <-- ERROR        

    public MyGeneric()
    {
        // All of the above errors would be errors here in constructor as well
    }
}

And the special method to initialize a generic field to its default value is the following:

class MyGeneric<T>
{
    T data = default(T);

    public MyGeneric()
    {           
        // The same method can be used here in constructor
    }
}
user1451111
  • 1,735
  • 3
  • 18
  • 30
0

"Prefer initialization in declaration", seems like a good general practice.

Here is an example which cannot be initialized in the declaration so it has to be done in the constructor. "Error CS0236 A field initializer cannot reference the non-static field, method, or property"

class UserViewModel
{
    // Cannot be set here
    public ICommand UpdateCommad { get; private set; }

    public UserViewModel()
    {
        UpdateCommad = new GenericCommand(Update_Method); // <== THIS WORKS
    }

    void Update_Method(object? parameter) 
    {
    }
}

Indy Singh
  • 27
  • 1
  • 5