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#
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".
The error is correct because if you create another instance of SomeClass the static field a will be assigned twice, against the readonly constraint.
You are trying to assign values to read only static variables inside a instance constructor. At the point you call the instance constructor that variables are already assigned a value, which 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 happens because the static constructor is called before the instance constructor. You can have more details here:
A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
But then, you have the problem when you are trying to access an instance variable inside the static constructor. At that point, the instance constructor is not yet called, which means your variable b is not yet initialized.
You are facing a very common problem, where you are trying to mix instance variables and static variables. This approach can lead to very strange behaviours, like the one you are facing.
I suggest to you to don't mix this variables, make them all static or or make them all instance, but don't mix it. Otherwise, you might face different problems in the near future
The error message is in fact correct.
First, static means it belongs to the class. Non static means it is per instance. An instance method can modify a static variable, but a static method cannot modify an instance variable (which instance would it modify?)
Given that, readonly means you can only initialize during creation (e.g. constructor.)
You are getting the error because you are trying to assign a readonly static AFTER its creation in an instance constructor.
Is there a wrong warning here?
No. The warning is correct. If a field is readonly, we can assign it a value in two places: upon declaration or in the constructor. Further, if something is static, its associated constructor is static too. So, we can assign to a static and readonly field in two places:
Upon declaration or
in the static constructor.
We cannot do it in an instance constructor.
Your other question is about the inability of a static field to depend on an instance one.
How do I circumvent this?
Here is a creative way to circumvent it:
In the static constructor, assign to static _b.
In the instance constructor, assign the static _b to the instance's b.
We can even assign _b = null when we're done with it and still access the value that we earlier assigned to b.
Here is 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(); }
}
}
It does let you circumvent the problem.
Related
I'm currently learning C# in Unity through a series of video tutorials and just had fields introduced. Am I correct in saying that fields are just variables declared in the class level?
Yes, you can say this.
The main difference is that variables in methods (also called local variables) have a temporary value used during the method call. The next time you call the method the previous value of the variables are lost and you have to initialize them again. (I am not talking about advanced stuff like iterators and captured variables.)
On the other side, variables in classes and structs, i.e. fields, are living as long as the object lives. I.e., they keep their value between method calls.
Unlike local variables that are first undefined, fields are assigned a default value when an object is created from a class. Struct fields behave differently depending whether the struct is used as class field or variable. The struct fields have thee same definedness as the field or variable defining them.
As #elgonzo commented, there are two types of fields
Static fields. They are declared with the static modifier. Static fields exist exactly once for a specific class or struct, independently of the number of objects of this type.
Instance fields exist once per object (i.e. class or struct instance).
Private instance fields can only be accessed by instance methods and constructors of this class or struct, where as private static fields can be accessed by static and instance methods and constructors. (Methods include getters and setters of properties and indexers.)
Example. With this class...
public class A
{
private static int _staticCounter;
private int _instanceCounter;
public void Count()
{
_staticCounter++;
_instanceCounter++;
}
public void PrintCount()
{
Console.WriteLine($"Static = {_staticCounter}, Instance = {_instanceCounter}");
}
public static void PrintStatic()
{
Console.WriteLine($"Static = {_staticCounter}"); // Can only access static fields.
}
}
...this test...
A x = new A();
A y = new A();
x.Count();
x.Count();
y.Count();
y.Count();
y.Count();
x.PrintCount();
y.PrintCount();
A.PrintStatic();
Console.ReadKey();
...prints this to the console
Static = 5, Instance = 2
Static = 5, Instance = 3
Static = 5
I am trying to understand need for static constructors. None of information I found answered following question I have. Why would you do this
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}
as opposed to this
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline = DateTime.Now.Ticks;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
//static SimpleClass()
//{
//}
}
?
This is not dupe of other question, this is about static constructors which don't accept parameters.
The need is somehow obvious: You want to do more than some field initialization for your static members.
Logically if you have this class:
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline = DateTime.Now.Ticks;
}
You can re-write it to have the same effect:
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
static SimpleClass () {
baseline = DateTime.Now.Ticks;
}
}
But instead, you could do more in your static constructor such as inspecting (using reflection) some properties and emiting some fast accessors / getters to them, or just simple notify other systems that your type has been created, etc.
From Jeffrey Richter CLR via C# book:
When the C# compiler sees a class with static fields that use inline
initialization (the BeforeFieldInit class), the compiler emits the
class’s type definition table entry with the BeforeFieldInit metadata
flag. When the C# compiler sees a class with an explicit type
constructor (the Precise class), the compiler emits the class’s type
definition table entry without the BeforeFieldInit metadata flag. The
rationale behind this is as follows: initialization of static fields
needs to be done before the fields are accessed, whereas an explicit
type constructor can contain arbitrary code that can have observable
side effects; this code may need to run at a precise time.
Obviouselly there is something more than this happening behind the scenes, I would suggest you to read entire chapter from CLR via C#: "Type Constructors"
This is an example of a possible difference:
class SimpleClass
{
static readonly long A = DateTime.Now.Ticks;
static readonly long B = DateTime.Now.Ticks;
static SimpleClass()
{
}
}
A and B are not guaranteed to be the same value, though if you were to write it in the constructor, you could guarantee it:
class SimpleClass
{
static readonly long A;
static readonly long B;
static SimpleClass()
{
var ticks = DateTime.Now.Ticks;
A = ticks;
B = ticks;
}
}
In addition, order matters for instantiation of static members.
According to ECMA-334 regarding static field initialization:
The static field variable initializers of a class declaration
correspond to a sequence of assignments that are executed in the
textual order in which they appear in the class declaration. If a
static constructor (§17.11) exists in the class, execution of the
static field initializers occurs immediately prior to executing that
static constructor. Otherwise, the static field initializers are
executed at an implementation-dependent time prior to the first use of
a static field of that class
So, we can write something like this:
class SimpleClass
{
public static readonly long A = IdentityHelper.GetNext();
public static readonly long B = IdentityHelper.GetNext();
static SimpleClass()
{
}
}
public static class IdentityHelper
{
public static int previousIdentity = 0;
public static int GetNext()
{
return ++previousIdentity;
}
}
Here, A is guaranteed to be assigned before B. In this example, A will be 1, and B will be 2. We can guarantee that A < B (assuming the identity does not overflow and there's no issues with threading). Now, if we re-order the fields:
public static readonly long B = IdentityHelper.GetNext();
public static readonly long A = IdentityHelper.GetNext();
The functionality changes. Thus, we've created a side-effect which is not immediately clear simply by re-ordering the fields definitions.
A more likely scenario is, we may want to do this:
class SimpleClass
{
public static readonly long A = IdentityHelper.GetExpensiveResult().A;
public static readonly long B = IdentityHelper.GetExpensiveResult().B;
static SimpleClass()
{
}
}
Here, we're unable to share GetExpensiveResult() between the fields.
Considering the following code:
public class Progressor
{
private IProgress<int> progress = new Progress<int>(OnProgress);
private void OnProgress(int value)
{
//whatever
}
}
This gives the following error on compilation:
A field initializer cannot reference the non-static field, method, or property 'Progressor.OnProgress(int)'
I understand the restriction it is complaining about, but I don't understand why it is an issue, but the field can be initialized in the constructor instead as follows:
public class Progressor
{
private IProgress<int> progress;
public Progressor()
{
progress = new Progress<int>(OnProgress);
}
private void OnProgress(int value)
{
//whatever
}
}
What is the difference in C# regarding the field initialization vs constructor initialization that requires this restriction?
Field initialization come before base class constructor call, so it is not a valid object. Any method call with this as argument at this point leads to unverifiable code and throws a VerificationException if unverifiable code is not allowed. For example: in security transparent code.
10.11.2 Instance variable initializers
When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable-initializers of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration.
10.11.3 Constructor execution
Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.
Everything in my answer is just my thoughts on 'why it would be dangerous to allow that kind of access'. I don't know if that's the real reason why it was restricted.
C# spec says, that field initialization happens in the order fields are declared in the class:
10.5.5.2. Instance field initialization
The variable initializers are executed in the textual order in which
they appear in the class declaration.
Now, let's say the code you've mentioned is possible - you can call instance method from field initialization. It would make following code possible:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string GetMyString()
{
return "this is really important string";
}
}
So far so good. But let's abuse that power a little bit:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
_third = "not hey!";
return "this is really important string";
}
}
So, _second get's initialized before _third. GetMyString runs, _third get's "not hey!" value assigned, but later on it's own field initialization runs, and it's being set to `"hey!". Not really useful nor readable, right?
You could also use _third within GetMyString method:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
return _third.Substring(0, 1);
}
}
What would you expect to be value of _second? Well, before field initialization runs all the fields get default values. For string it would be null, so you'll get unexpected NullReferenceException.
So imo, designers decided it's just easier to prevent people from making that kind of mistakes at all.
You could say, OK let's disallow accessing properties and calling methods, but let's allow using fields that were declared above the one you want to access it from. Something like:
public class Progressor
{
private string _first = "something";
private string _second = _first.ToUpperInvariant();
}
but not
public class Progressor
{
private string _first = "something";
private string _second = _third.ToUpperInvariant();
private string _third = "another";
}
That's seems useful and safe. But there is still a way to abuse it!
public class Progressor
{
private Lazy<string> _first = new Lazy<string>(GetMyString);
private string _second = _first.Value;
private string GetMyString()
{
// pick one from above examples
}
}
And all the problems with methods happen to come back again.
Section 10.5.5.2: Instance field initialization describes this behavior:
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
This behavior applies to your code because OnProgress is an implicit reference to the instance being created.
The answer is more or less, the designers of C# preferred it that way.
Since all field initializers are translated into instructions in the constructor(s) which go before any other statements in the constructor, there is no technical reason why this should not be possible. So it is a design choice.
The good thing about a constructor is that it makes it clear in what order the assignments are done.
Note that with static members, the C# designers chose differently. For example:
static int a = 10;
static int b = a;
is allowed, and different from this (also allowed):
static int b = a;
static int a = 10;
which can be confusing.
If you make:
partial class C
{
static int b = a;
}
and elsewhere (in other file):
partial class C
{
static int a = 10;
}
I do not even think it is well-defined what will happen.
Of course for your particular example with delegates in an instance field initializer:
Action<int> progress = OnProgress; // ILLEGAL (non-static method OnProgress)
there is really no problem since it is not a read or an invocation of the non-static member. Rather the method info is used, and it does not depend on any initialization. But according to the C# Language Specification it is still a compile-time error.
So I have a function:
List<string> names = new string();
private static void getName(string name)
{
names.add(name);
}
When I attempt to compile I get a:
'object reference is required for the non-static field' notice.
What do I have to do to make this member (names) compatible with getName?
I need it to be non static or converted because I want to put the results into other non static functions and forms.
You need to tell the system which list of names you're interested in. It's part of the state of an object, an instance of the class... but which one? Maybe you've created several instances of the class - maybe you've created no instances of the class. The static method has no visibility of that - so which instance do you want it to fetch the names variable value from?
To put it in another example, suppose we had a class like this:
public class Person
{
public double MassInGrams { get; set; }
public double HeightInMetres { get; set; }
public static double ComputeBodyMassIndex()
{
// Which person are we interested in?
}
}
Person p1 = new Person { MassInGrams = 76203, HeightInMetres = 1.8 };
Person p2 = new Person { MassInGrams = 65000, HeightInMetres = 1.7 };
double bmi = Person.ComputeBodyMassIndex();
What would you expect the result to be? You've asked the Person class to compute "the BMI" but without telling it whose BMI to compute. You need to give it that information.
Some options for your situation:
Change names to be static instead
Change the method to be an instance method
Pass in an instance of the class
Create an instance of the class, possibly returning it
Fetch an instance of the class some other way
By the way, that's a very strange method name for something which adds a name. It's also somewhat unconventional...
You need to make names static if you want to use it from inside of a static method:
// If this is static, you can use it from your static method
static List<string> names = new List<string>();
The issue is that getName is defined on your type, not on an instance of the type. However, names is defined so each instance of your type gets its own value.
names is an object that will exist in the instances of the class e.g. MyClass mc = new MyClass(); then you can access mc.names. A static field can be called without an instance of the class just with the classname, e.g. MyClass.getName(""); will work. So when you think logically, the class doesn't contain names, only 'the instances of that class' contain it. Therefore, you either make that list static too and it will be 'the same List instance' everywhere when you call MyClass.names or make the getName method non-static, and it will be only called from instances, therefore no MyClass.getName("") will be possible, but mc.getName(""); It's a matter of what you are exactly trying to do.
Static methods can not access class fields. Either make names static, or make getName() non-static. What do you mean by "Compatible". Ask yourself... does the method need to be static? What is its purpose and how do you intend to use it?
You cant access it this way, you need to instanciate the class containing a member.
I want to understand the difference between 3 sets of snippets below:
private static FirstObject o = new FirstObject();
public class ClassA
{
}
//-----------------------------------------------------
public class ClassA
{
private static FirstObject o = new FirstObject();
}
//-----------------------------------------------------
public class ClassA
{
private static FirstObject o;
public ClassA
{
o = new FirstObject();
}
}
Please help me understand in terms of scope, memory, performance and usage of these.
Thank you.
Invalid, as you can't have a variable outside of object
The proper way - the class has a static member, which is initialized when the class is accessed for the first time
Very bad, because every time when new object is created the static object will be recreated.
The first option will not compile. A static variable in C# must be scoped to a class or struct.
The second option is the preferred mechanism.
The third option is wrong because this creates a new FirstObject each time an instance of ClassA is created, which is almost certainly not what you want.
A fourth option would be to leverage a static constructor, e.g.,
public class ClassA
{
private static FirstObject o;
static ClassA
{
o = new FirstObject();
}
}
This option is useful if there is some special construction constraints for FirstObject. In this example, though, choose option 2 over option 4. Just know that option 4 exists.
Three cases below...
Assuming a typo here missing some outer construct... "o" is declared so that it will be globally accessible, as a single object, to the entire application. It will have one common set of all properties and data. It can be access directly by "Namespace.o"
"o" is declared so that it will be globally accessible, as a single object, to the entire application, However it is only accessible through another defined instance of "ClassA". Each separate instance of ClassA will have the same, single "o" object with the same properties and data.
This doesn't look right to me, I'm assuming "ol" is supposed to "o;". Even with this the code looks like its missing something. if the Line "o = new FirstObject" is correct it is not accessible in this fashion.