Clarifying Understanding of Fields - c#

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

Related

What is the real difference between a static member and a constant in C#?

I'm learning C#,and now i'm trying to understand static members and constants.Which is the best way to declare a constant?
This way?
class Myclass
{
public const double G=9.8;
}
Or
class Myclass
{
private static double G{get;set;}
static MyClass()
{
G=9.8;
}
}
I've asked this question because,with the 2 ways i access the membre with the same code:
Console.WriteLine(Myclass.G);
constant:
Constant fields are defined at the time of declaration in the code
snippet, because once they are defined they can't be modified. By
default a constant is static, so you can't define them static from
your side.
It is also mandatory to assign a value to them at the time of
declaration otherwise it will give an error during compilation of the
program snippet. That's why it is also called a compile-time constant.
Explanation:
Consider ff. code:
void Sum(int j)
{
const int i = 9, k = 2;
const int A = i + k;
}
This will produce a result of 11, without showing any error since we already declared it at the initial point of declaration.
But how about:
void Sum(int j)
{
const int i = 9, k = 2;
//const int A = i + k;
Const int B = i + j;
}
This code snippet will take you toward a compile-time error, because there is no initialization, since it's evaluated at run time.
Points to Remember
Compile-time constant
Can't be declared static
Can't be modified or changed
Can be of any type of Access Modifier
Local scope
Needs to get initialized
Declared at the time of declaration
Static
The static keyword is used to declare a static member. If we are
declare a class as a static class then in this case all the class
members must be static too. The static keyword can be used effectively
with classes, fields, operators, events, methods and so on
effectively.
Consider ff. code:
class ReadOnly
{
static int i = 11;
public static void disp()
{
Console.WriteLine(i);
}
}
Explanation:
This code will show no error and produce a result (11), since we declared its value to be static at the time of declaration. So we can access it depending on our use in the program.
But how about this:
class ReadOnly
{
int i = 9;
public static void disp()
{
Console.WriteLine(i);
}
}
This snippet above will show an error, because we didn't declare a value for the static and we are trying to access it within a method. We can't do that.
Points to Remember:
Can't be used with indexers
Works with constructors too
By default it is private
Can be parameterized or public too
If its applied to a class then all the class members need to be static
You can read more about above explanation here: constant vs readonly vs static
Additional note for static methods.
Consider ff. code:
public class SomeClass {
public string SomeMethod() {
return "Hello, World.";
}
}
When you want to Access SomeMethod of SomeClass, you need to instantiate SomeClass first:
var some = new SomeClass();
string result = some.SomeClass(); //this will set result as "Hello, World."
Compared to a static method:
public class SomeClass {
public static string SomeMethod() {
return "Hello, World.";
}
}
When accessing SomeMethod, you don't need to instantiate SomeClass. You can access it directly by:
string result = SomeClass.SomeMethod(); //this will give "Hello, World."
Which is the best way to declare a constant?
Its not the best, its the only way: const double G = 9.8;.
Or (...) static double G { get; set; }
Thats not a constant! Constant means constant: 1 is a constant, 'c'is a constant, PI is a constant... they represent values that don't change, ever!. Your second implementation of G can change, therefore its not a constant.
Also, its important you notice that constants are known at compile time, there is no evaluation needed at runtime.
This is the reason why any reference type const (expect string which has specific compiler support through string literals) can only be initialized to null, any other option would need to be evaluated at runtime.
Its also the reason why only a finite set of value types can be declared as const too. All of them are existing types in the framework and.. surprise, surprise, they all have compiler literal constant support: 1, 'c', 9.8 or 0.25M but not 01/01/2017 (how else would the compiler know the values before runtime?).
Another interesting question you didn't make is: what about static readonly?
You can think of static readonly as "the poor man's" const. Its often used to circumvent the limitations const offers concerning what types and initializing values are allowed.
It is almost the same as a constant, but there are a few important and decisive differences:
It can change; although it is readonly, you can change it's value inside the static constructor of the declaring type. const can never change after initialized.
It is evaluated at runtime, not compile time as a true const.
Any type can be declared as a static readonly and initialized to any valid value as you would do with any regular field.
As a nittpicking side note, you shouldn't make G a constant ;). It changes, and quite a bit. G in Ecuador is different from G in the North Pole.
const variables are assigned values at time of definition.
They are available at compile time. You can even use a compile time evaluate-able expression at compile time. But once a value has been assigned to a const variable, it cannot be changed at any other time.
Using static field means the value will remain same for every user of the application, but this value can be changed by code in any of the classes, and it will change for every user of the application.
Do not use static for constants, use const only. const are by default static, and you cannot use static keyword with it.
Check this
void Main()
{
// You will not be able to change value for const variable.
Console.WriteLine(Myclass.G);
// You will be able to change value for static variable,
// and this change will impact all users of the application.
// For every user, this field will store value of 10 now.
// That will not be required or desired code behavior.
Myclass1.G = 10;
Console.WriteLine(Myclass1.G);
}
// Normal class with const field
class Myclass
{
public const double G=9.8;
}
//static class with static constructor
static class Myclass1
{
public static double G{get;set;}
static Myclass1()
{
G=9.8;
}
}
Read More
Here you are talking about two different things, and this is their definition from MSDN:
1- static modifier: To declare a static member, which belongs to the type itself rather than to a specific object. The static modifier can be used with classes, fields, methods, properties, operators, events, and constructors, but it cannot be used with indexers, finalizers, or types other than classes.
2- const keyword: To declare a constant field or a constant local. Constant fields and locals aren't variables and may not be modified. Constants can be numbers, Boolean values, strings, or a null reference. Don’t create a constant to represent information that you expect to change at any time.
So a static member is defined for a Class (for all its instances, and that's why you can access it directly from the name of the Class) but can be modified. a const field of class can not be modified.

'private static readonly' fields and static/nonstatic 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());
}
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.

Code design, assigning static constant

In my app I have a static class called Constants which holds all of my global values which are accessed throughout my project. A section of Constants looks like so:
internal static class Constants
{
internal static DateTime FromDate = new DateTime(2011, 10, 1);
internal static DateTime ToDate = new DateTime(2011, 10, 31);
internal static decimal TaxRate = 20m;
}
However now TaxRate is to be accessed dynamically from the database (and subsequently is available through an instance of an repository). However since static constructors cannot have parameters how can I achieve this?
I'd like Constants to keep it's same properties:
It's static, hence cannot be instantiated and have different versions
It's properties cannot be modified (because of the const modifier)
However I'd also like to be able to set TaxRate from a reference object for the first time only.
What would be the best design to achieve this?
Instead of using a "Static" class for this, why not consider using an IoC container with a scope of the usage of the class to be a Singleton() usage, or simply implement a singleton pattern against your Constants class, and then set the properties of the class to be a public getter with a private setter... you can then call an initialize() method to pull the required info from the database, but the rest of the code shouldn't be able to affect the values of the properties.
e.g.:
public class Constants
{
static Constants instance;
public static Constants Instance
{
get
{
if (instance == null)
{
instance = new Constants();
instance.Initialize();
}
}
}
public void Initialize()
{
// db logic here to populate db recorded fields.
}
private Constants()
{
}
}
You could make them all Properties rather than instance variables that aren't private. You can then provide getters without setters so that they cannot be modified elsewhere.
As for the complex initialization, you could then use lazy loading (if you make it thread safe). Have private variables that aren't set, and when you 'get' one, if it isn't initialized, initialize it.

C# accesing non static member in a static function

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.

How can I ensure this private readonly array is actually private and readonly?

I'm trying to figure out how I am able to successfully change a "readonly" array. The code below runs successfully, but I'm quite confused as to why the dereferencing of a private/readonly array is legal, as marked below:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Time[5] = 5; // Why is this legal? How can I make it illegal?
}
}
public class MyClass
{
private readonly uint[] time;
public IList<uint> Time
{
get { return time; }
}
public MyClass()
{
time = new uint[7];
}
}
}
As I Note above, I would expect that Time[5] would be illegal due to the fact that public IList Time does not have a setter.
How can I change MyClass to ensure that it is not legal to do myClass.Time[5] ?
Note: I've clarified the intent of this question, I was unclear at the start that the intention is to make this ILLEGAL. And I want to understand why its legal in the first place as is.
As I Note above, I would expect that
Time[5] would be illegal due to the
fact that public IList Time does not
have a setter.
The absence of a setter means that you can't assign a NEW ARRAY to the backing field of the property, but it doesn't mean that you can't change the CURRENT array reference that the backing field is pointing to.
Additionally, how can I create an
array in the constructor which is
read-only and unchangeable outside of
this class?
You can instatnitate a readonly field either at the declaration stage or in the constructor of the class as per MSDN.
As for how to fix this, the following MSDN article discuses this exact issue and some way to remedy it. I am not sure what your requirements are, but I would recommend looking into implementing a custom collection using ReadOnlyCollectionBase then passing that along or you can use ReadOnlyCollection<T>. The link to the ReadOnlyCollectionBase provides an example of an implementation.
readonly means that the field itself cannot be changed (that is, you cannot say "this.time = new uint[10]" outside the constructor). Arrays are mutable objects, so anywhere you have a reference to the array, the possessor of that reference can change the values stored in that array.
readonly fields are writable only in the constructor (this includes field initializers)
Two options for you:
Do a shallow copy of the array in the Time property, so callers can't modify your copy of the array
Use ReadOnlyCollection to prevent modifications at all
Time property hasn't setter so you will be not able to do something like this:
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Time = new List<uint>();
}
but you are able to use indexer so Time[5] is legal.
Additionally, how can I create an array in the constructor which is read-only and unchangeable outside of this class?
read-only fields can be initialized in constructor only. Initialization right after declaration is the same as initialization in constructor.

Categories

Resources