'private static readonly' and static / non-static constructors

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());
}

      

This is giving me an error Readonly field cannot be used as an assignment target

. If I remove either the static or readonly modifiers it compiles fine. (Is there a wrong warning here?)

While checking the other answers here on SO I found that I have to use a static constructor like:

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

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

      

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

How do I get around this?

PS I am relatively new to C #

+3


source to share


5 answers


Let's start by defining what is static

and what is the difference between the members static

and instance

.

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

Now the modifier readonly

says that only a value can be assigned to a member in the constructor (or in its declaration, but that doesn't matter here).

There are two types of constructors: static constructors and instance constructors ... the difference is the same difference as above and the modifier of readonly

course applies to each type of constructor: static readonly

would mean "you can only change its value in a static constructor" and instance readonly

means "you can change its value in the instance constructor".

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

Now in the examples you just randomly change the members to, static

or don't just try if they compile.



Think about it for a second ... in context static

, you don't have an instance at all, so it just isn't possible to access the instance instances in the constructors static

... besides, by the time a static constructor is called and you can't have any an initialized instance, even externally defined, as it will always be called before you can initialize it.

So this line inside a static constructor doesn't make sense:

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

      

You are trying to access b

which is a member of an instance, but you are not saying which instance should get the value.

You should really rethink your design and think about why the members will be static or not, rather than just "move things around and try to compile and run".

+4


source


The error message is actually correct.

First, static means it belongs to the class. Non-stationary means it is one instance. An instance method can change a static variable, but a static method cannot change an instance variable (which instance would it change?)



Considering readonly means you can only initialize at creation time (e.g. constructor.)

You are getting an error because you are trying to assign a static PERMANENT to a static AFTER creating it in the instance constructor.

+1


source


The error is correct, because if you create another instance of SomeClass, the static field a will be assigned twice, against the readonly constraint.

+1


source


You are trying to assign read-only values ​​to static variables inside an instance constructor. The moment you call the instance constructor, the variables are already assigned a value that is null.

public SomeClass()
{
    a = new Apple(); // it is already assigned as null. 
    b = new Orange(a.getDna()); //there is no value assigned to it yet
    c = new Apple(b.getDna()); //it is already assigned as null
}

      

This is because the static constructor is called before the instance constructor. You can get more information here :

The static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

But then the problem arises when you try to access an instance variable inside a static constructor. At this point, the instance constructor hasn't been called yet, which means that your variable b

hasn't been initialized yet.

You are facing a very common problem when you are trying to mix instance and static variables. This approach can lead to very strange behavior like the one you are encountering.

I suggest that you don't mix these variables, make them static, or make them all instances, but don't mix them. Otherwise, you may face various problems in the near future.

+1


source


Is there an incorrect warning here?

Not. The warning is correct. If a field readonly

, we can assign a value to it in two places: in the declaration or in the constructor. Also, if something is there static

, so is its associated constructor static

. Thus, we can assign fields static

, and readonly

in two places:

  • After the announcement or
  • in the constructor static

    .

We cannot do this in the instance constructor.

Another question is about the inability of the field to static

depend on the instance.

How do I get around this?

Here's a creative way to get around it :

  • In the constructor, static

    assign static _b

    .
  • In the instance constructor, assign to the static _b

    instance b

    .

We can even assign _b = null

when we're done with it and still access the value we previously assigned b

.

Here's an example:

public class SomeClass
{
    private static readonly Apple a, c;
    private static Orange _b;
    private readonly Orange b;

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

    public SomeClass()
    {
        b = _b;
        _b = null;
    }

    //
    // the rest is just class definitions
    //      

    public class Apple
    {
        public Apple(object o = null) {}
        public object getDna() { return new object(); }
    }

    public class Orange
    {
        public Orange(object o = null) { }
        public object getDna() { return new object(); }
    }
}

      

This allows you to work around the problem.

+1


source







All Articles