129

I have a class and when I try to use it in another class I receive the error below.

using System;
using System.Collections.Generic;
using System.Linq;

namespace MySite
{
    public class Reminders
    {
        public Dictionary<TimeSpan, string> TimeSpanText { get; set; }

        // We are setting the default values using the Costructor
        public Reminders()
        {
            TimeSpanText.Add(TimeSpan.Zero, "None");
            TimeSpanText.Add(new TimeSpan(0, 0, 5, 0), "5 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 15, 0), "15 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 0, 30, 0), "30 minutes before");
            TimeSpanText.Add(new TimeSpan(0, 1, 0, 0), "1 hour before");
            TimeSpanText.Add(new TimeSpan(0, 2, 0, 0), "2 hours before");
            TimeSpanText.Add(new TimeSpan(1, 0, 0, 0), "1 day before");
            TimeSpanText.Add(new TimeSpan(2, 0, 0, 0), "2 day before");
        }

    }
}

Using the class in another class

class SomeOtherClass
{  
    private Reminders reminder = new Reminders();
    // error happens on this line:
    private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
    ....

Error (CS0236):

A field initializer cannot reference the nonstatic field, method, or property

Why does it happen and how to fix it?

0

6 Answers 6

175

This line:

private dynamic defaultReminder = 
                          reminder.TimeSpanText[TimeSpan.FromMinutes(15)];

You cannot use an instance variable to initialize another instance variable. Why? Because the compiler can rearrange these - there is no guarantee that reminder will be initialized before defaultReminder, so the above line might throw a NullReferenceException.

Instead, just use:

private dynamic defaultReminder = TimeSpan.FromMinutes(15);

Alternatively, set up the value in the constructor:

private dynamic defaultReminder;

public Reminders()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
}

There are more details about this compiler error on MSDN - Compiler Error CS0236.

11
  • 3
    Java is more 'forgiving' for these kind of constructs. Don't know whether that is a good thing. stackoverflow.com/questions/1494735/… Commented Feb 3, 2015 at 11:52
  • 46
    No, the compiler cannot rearrange the initializers. The C# Language Specification states, under the section "10.5.5.2 Instance field initialization", the following: The variable initializers are executed in the textual order in which they appear in the class declaration. This is even repeated in "10.11.2 Instance variable initializers" where they say: The variable initializers are executed in the textual order in which they appear in the class declaration. So your explanation is wrong. The order is fixed. The reason why it is disallowed is that the designers of C# wanted it that way. Commented Apr 18, 2016 at 20:16
  • 1
    (Only in the case of a partial class with "parts" in several files is the order of the field initializers unclear, but that goes for static fields as well!) Commented Apr 18, 2016 at 20:18
  • 1
    @WouterSchut The thread you link is not about Java?! It is about C# as well, however with static fields instead of instance fields. Commented Apr 18, 2016 at 20:33
  • 2
    @Andrew Not true at all, Many decisions are made to forbid bad practices. even though they can, theoretically, be implemented, some guarded by Warnings, and some are plain Errors. and i think that this is one of these cases... even though the standard says it's sequencial, even an experienced developer wouldn't say it with confident (without searching the standard).
    – Tomer W
    Commented Nov 7, 2017 at 18:42
30

You need to put that code into the constructor of your class:

private Reminders reminder = new Reminders();
private dynamic defaultReminder;

public YourClass()
{
    defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

The reason is that you can't use one instance variable to initialize another one using a field initializer.

0
11

you can use like this

private dynamic defaultReminder => reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
3
  • 11
    Welcome to Stack Overflow! While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, as this reduces the readability of both the code and the explanations!
    – jmattheis
    Commented Aug 6, 2016 at 19:46
  • 6
    It's using => instead of = thus making it a property.
    – Vincent
    Commented Dec 24, 2016 at 1:15
  • 11
    Be careful using this technique, since using => doesn't set the actual value, but will execute the code each time defaultReminder is accessed. This may not be intended, and have a negative performance impact, or generate unwanted pressure for GC, etc.
    – Smilediver
    Commented Apr 16, 2020 at 18:22
9

private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; is a field initializer and executes first (before any field without an initializer is set to its default value and before the invoked instance constructor is executed). Instance fields that have no initializer will only have a legal (default) value after all instance field initializers are completed. Due to the initialization order, instance constructors are executed last, which is why the instance is not created yet the moment the initializers are executed. Therefore the compiler cannot allow any instance property (or field) to be referenced before the class instance is fully constructed. This is because any access to an instance variable like reminder implicitly references the instance (this) to tell the compiler the concrete memory location of the instance to use.

This is also the reason why this is not allowed in an instance field initializer.

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 only type members that are guaranteed to be initialized before instance field initializers are executed are class (static) field initializers and class (static) constructors and class methods. Since static members are instance independent, they can be referenced at any time:

class SomeOtherClass
{
  private static Reminders reminder = new Reminders();

  // This operation is allowed,
  // since the compiler can guarantee that the referenced class member is already initialized
  // when this instance field initializer executes
  private dynamic defaultReminder = reminder.TimeSpanText[TimeSpan.FromMinutes(15)];
}

That's why instance field initializers are only allowed to reference a class member (static member). This compiler initialization rules will ensure a deterministic type instantiation.

For more details I recommend this document: Microsoft Docs: Class declarations.

This means that an instance field that references another instance member to initialize its value, must be initialized from the instance constructor or the referenced member must be declared static.

2

i am totally surprised about the accepted answer here by the community which is totally wrong, accepted answer says:

Because the compiler can rearrange these

as "Jeppe Stig Nielsen" says in a comment of accepted answer:

The C# Language Specification states: The variable initializers are executed in the textual order in which they appear in the class declaration

which doesn't mean that C# is an interpreting language, but it also doesn't mean that C# can rearrange lines of code!

so finally why this error happens? assume below code:

public class MyClass
{
    public int i = 5;
    public int j = i;  // CS0236

    public MyClass()
    {
        // ...
    }
}

let me show you how C# compiler see this code:

public class MyClass
{
    public int i = 5;
    public int j = this.i;  // CS0236

    public MyClass()
    {
        // ...
    }
}

"this" keyword which appears in public int j = this.i; reference MyClass class, but MyClass doesn't exist yet, why? because classes start their existence when their constructors end their executions and in C# logic constructors are executed last , which means they will be executed after instance field/variable initializers, so in public int j = this.i; expression, this is referring to nothing!

0

You should initialize in the constructor. so do this:

    class SomeOtherClass
    {  
        private Reminders reminder ;
        // error happens on this line:
        private dynamic defaultReminder ;

    public SomeOtherClass()
    {
remider = new Reminders();
    defaultReminder =reminder.TimeSpanText[TimeSpan.FromMinutes(15)]; 
      }

Not the answer you're looking for? Browse other questions tagged or ask your own question.