'private static readonly' fields and static/nonstatic constructors

Hele picture Hele · Apr 21, 2015 · Viewed 11.7k times · Source

I have three objects :

private static readonly Apple a, c;
private readonly Orange b;

This code is called from my constructor :

public SomeClass()
{
    a = new Apple();
    b = new Orange(a.getDna());
    c = new Apple(b.getDna());
}

It gives me the error Readonly field cannot be used as an assignment target. If I remove either the static or readonly modifiers, it compiles perfectly. (Is there a wrong warning here?)

On checking other answers here on SO, I found that I should use a static constructor like :

static SomeClass()
{
    a = new Apple();
    c = new Apple(b.getDna());
}

public SomeClass()
{
    b = new Orange(a.getDna());
}

But this would cause the static constructor to be called first and cause an error since b would not be initialized.

How do I circumvent this?

P.S. I'm relatively new to C#

Answer

Jcl picture Jcl · Apr 21, 2015

Let's start by defining what is static and what's the difference between static and instance members.

A static member is a member that doesn't need an instance to exist: it "belongs to the class", and not to an object (a instance of the class).

Now the readonly modifier, says that a member can only be assigned a value in the constructor (or in its declaration, but that's not relevant here).

There are two types of constructors: static constructors and instance constructors... the difference is the same difference as above, and the readonly modifier is of course, applied to each type of constructor: static readonly would mean "you can only change its value in the static constructor", and instance readonly would mean "you can change its value in the instance constructor".

The static constructor is called the first time the type is accessed, so it's always called first.

Now, in the examples you are just randomly changing members to static or not just to try if it compiles.

Think about it for a second... in the static context you have no instance at all, so it's just not possible to access instance members on the static constructors... furthermore, by the time the static constructor is called, there's no way you could have any initialized instance, even externally defined, since it'll always be called before you have the chance to initialize one.

So this line within the static constructor makes no sense:

c = new Apple(b.getDna());

You are trying to access b, which is an instance member, but you are not saying which instance should you get the value from.

You should really rethink your design, and think why members would be static or not, not just "move things around and try to make it compile and run".