Creating a shared static field in c# - c#

The question that I have is in regards to creating a shared field that is Static within an instance class. The code that I am going to display works perfectly fine. What I am really wanting to grasp is the understanding behind the logic. Here is a code snippet which is of a very basic class and a method which creates objects from this class and displays to the screen how many objects have been created.
public class Counter
{
private int value;
private static int ValueCounter = 0;
public Counter()
{
value = ValueCounter;
ValueCounter++;
}
public static int objectCount()
{
return ValueCounter;
}
}
Above is a very basic but working class. I am trying to keep it as simple and as basic as possible so that I get the understanding of it.
Below is now the code snippet that creates instances of the class and displays to the screen how many instances have been created.
private static void showObjectCounter()
{
Counter val1 = new Counter();
Counter val2 = new Counter();
Counter val3 = new Counter();
Counter val4 = new Counter();
int totalValue = Counter.objectCount();
Console.WriteLine("Total objects created = {0}", totalValue);
}
Now this is my question regarding this matter. When a new object is created the value field is independent of each instance hence each object gets there own copy. However the static field is a shared field and incremented with each new creation of an object. I was wondering if this increment value is saved after each creation of the new object i.e one object is created value is incremented to 1, then another object is created and the last value of the increment was at 1 so now it is incremented to 2 and so on for each new object creation.
Or does each new object that is created get incremented to 1 and then are all added together to find the total value of the objects created ?
It is a very basic and simple question but Iam fighting with myself over which is ryt or wrong prob because of the time of nyt that it is. Anyhow if anyone has a simple answer to a very simple question then please feel free to share it.
Thanks.

It's really a shared value, so every time a constructor runs, the value is incremented by 1 regardless of when the variable is accessed thereafter. You could verify this yourself:
private static void showObjectCounter()
{
Counter val1 = new Counter();
Console.WriteLine("Total objects created = {0}", Counter.objectCount());
Counter val2 = new Counter();
Console.WriteLine("Total objects created = {0}", Counter.objectCount());
Counter val3 = new Counter();
Console.WriteLine("Total objects created = {0}", Counter.objectCount());
Counter val4 = new Counter();
Console.WriteLine("Total objects created = {0}", Counter.objectCount());
}
You'll see that value changes every time.

You might be helped by using some conventional naming and coding style.
Use this for instance variables
Use C# Property instead of getter/setter method
Don't use this for static variables
Slightly more descriptive naming
Sample:
public class Counter
{
public int Count { get; }
private static int instanceCounter = 0;
public static int InstanceCount
{
get
{
return instanceCounter;
}
}
public Counter()
{
this.Count = instanceCounter;
instanceCounter++;
}
}

In your example, there is only one physical location in memory that corresponds to the ValueCounter variable.
By contrast, the non-static value field is stored in each instance's object data.

Related

returning functions vs void functions setting variables

New programmer here, I just wondered about this for a while. Take a look at this for instance, what is the difference between these ?:
static void Main(string[] args)
{
Program obj = new Program();
Console.WriteLine(Convert.ToString(obj.Add()));
}
int Add()
{
return 1 + 1;
}
and
int Sum;
static void Main(string[] args)
{
Console.WriteLine(Convert.ToString(Sum));
}
void Add()
{
Sum = 1+1;
}
The first case executes the method Add and prints the return value 2 to the console.
The second case will not compile because Sum is a class variable and you are missing a object reference like in the first case to access it.
If you would make Sum static then your Main will work and print simply the default value of Sum which is 0. Since you never call the Add method.
As for the difference of the two Add() methods:
The second case uses a class variable and manipulates it. It has to be called so that the value of Sum changes.
The first case uses only a local computation and does not change anything within the class. It simply returns the result of a calculation
EDIT:
What would be the difference between the two, which will be preferable?
It depends strongly on what you intend to do. If the only thing you are interested is the result of 1+1 and you need to use this result in some method like the Main then use the first case.
If the variable represents a significant feature of the class like this:
public class BillsToPay
{
public int Sum;
List<int> Bills = new List<int>() {3,5,6,7};
public void CalculateAllBills()
{
foreach (var bill in Bills)
{
Sum = Sum + bill;
}
}
}
Then you would have a method which manipulates the class variable Sum and updates its state. so the second version kicks in. But it is always a mixture of taste and intention of how to approach a given problem.
Small test program:
static void Main(string[] args)
{
BillsToPay btp = new BillsToPay();
btp.CalculateAllBills();
Console.WriteLine(Convert.ToString(btp.Sum));
}

Adding CustomClassObjects to Dictionary as values

I have a task where I need to have two values for one key in Dictionary.
Solution found in web is to make new class with two fields and use it's objects as values.
But how can I assign value to my CustomClassObjects from Dictionary's for loop?
Here is the code:
Dictionary<char, Huffmans> HuffmanDictionary = new Dictionary<char, Huffmans>();
Program.text = File.ReadAllText(Program.sourcetext);
char character;
for (int i = 0; i < Program.text.Length; i++)
{
counter++;
character = Convert.ToChar(Program.text[i]);
if (HuffmanDictionary.ContainsKey(character))
HuffmanDictionary[character].probability++;
else
HuffmanDictionary.Add(character, 1);// here is the problem, obviously program can't assign value directly to class...
}
public class Huffmans
{
public int code = 0;
public double probability = 0;
}
Basically, I need to assign only "probability" values on this step. Should I call constructor for "Huffmans " on each iteration?
Big thanks for any help, Alex
You need to instantiate your class before adding the value:
HuffmanDictionary.Add(character, 1);
Should be:
HuffmanDictionary.Add(character, new Huffmans{ code = 1 });
Alternatively you can create a constructor for your class:
public class Huffmans
{
public Huffmans(int _code)
{
code = _code;
}
public int code = 0;
public double probability = 0;
}
then you can do:
HuffmanDictionary.Add(character, new Huffmans(1));
EDIT:
Some more clarification:
HuffmanDictionary.Add(character, 1);
fails because you are passing a type int into the dictionary but it is expecting the type Huffmans. Our dictionary is : Dictionary<char,Huffmans>()
HuffmanDictionary.Add(character, new Huffmans{ code = 1 });
works because now we are creating a new object of type Huffmans and we are setting the code value to 1.
Not sure if I understood your comment correctly, but effectively we are doing the same as:
var newHuffmans = new Huffmans{ code = 1 };
HuffmanDictionary.Add(character, newHuffmans);
But rather than writing out all that code and creating a named variable with our class, we skip this and pass it directly into the dictionary.

C# Struct array but not class array

I was able to create an array of a struct I created, but I'm having trouble doing the same for an array of a class. I'm (faintly) aware that this probably isn't the best way to do this, but I'd appreciate help in figuring out what's going on.
I'm about 2 days into learning C#, and I'm navigating away from MS Office-VBA, if that gives you an idea of what I'm into. Anyway, I'm following an online reference, and along the way trying to play with what I've learned so far. This problem has come about as a result of my playing.
First, let me describe what I've done with the struct, and the array of that struct, with some code snippets.
I've been able to create a struct, called Machines...
// play with structs
struct Machines
{
// vars for struct
private string model, SN;
private int hours;
// assign values
public void AssignValues(string model_in, string SN_in, int hours_in)
{
model = model_in;
SN = SN_in;
hours = hours_in;
}
// display values
public void DisplayValues()
{
Console.WriteLine("Model: {0}", model);
Console.WriteLine("SN: {0}", SN);
Console.WriteLine("Hours: {0}", hours);
}
};
... things seem to work just fine:
public static void Main()
{
// play with structures
Machines machine1 = new Machines();
machine1.AssignValues("AA", "ABC01234", 34760);
machine1.DisplayValues();
Output is:
Model: AA
SN: ABC01234
Hours: 34760
Then, I can create an array of the struct, and things continue to go well:
// play with structures and arrays
// declare, create new instance
Machines [] MyArr = new Machines[10];
MyArr[0].AssignValues("AA", "ABC01235", 43000);
MyArr[0].DisplayValues();
But, when I attempt to do the same with a class, it's a different story. What's going on?
public class ArmstrongMachine
{
// vars for struct
private string model, SN;
private int hours;
// assign values
public void AssignValues(string model_in, string SN_in, int hours_in)
{
model = model_in;
SN = SN_in;
hours = hours_in;
}
// display values
public void DisplayValues()
{
Console.WriteLine("Model: {0}", model);
Console.WriteLine("SN: {0}", SN);
Console.WriteLine("Hours: {0}", hours);
}
};
...
// play with classes
ArmstrongMachine [] MyMachines = new ArmstrongMachine[10];
MyMachines[0].AssignValues("AA", "ABC01236", 51000);
MyMachines[0].DisplayValues();
The issue seems to begin with MyMachines[0].AssignValues.... If I comment out that line and the following, there are no problems (other than the warning that I've created a variable I'm not using).
Any ideas?
Also, please be aware that this is being compiled online.
A class gives you a reference type in C#.
The array thus holds references to objects, and not the objects themselves.
The array initially contains nothing, all zeroes, which means all the references will be null.
You need to initialize each element of the array to hold an object reference:
// play with classes
ArmstrongMachine [] MyMachines = new ArmstrongMachine[10];
MyMachines[0] = new ArmstrongMachine();
MyMachines[0].AssignValues("AA", "ABC01236", 51000);
MyMachines[0].DisplayValues();
MyMachines[1] = new ArmstrongMachine();
MyMachines[2] = new ArmstrongMachine();
...
MyMachines[9] = new ArmstrongMachine();
If the array holds value types, like the structs, then the array holds the struct values themselves, thus it works with the structs, and not with the objects.
Also note that you should emphatically not use mutable structs (structs you can change). There's tons of things that can go wrong and bite you in ... so you should not use them. Go with classes in this case.
Here's a video on the subject of mutable structs: Evil Structs, by Jon Skeet.
In simple words: A struct is only a way the memory is structured whereas a class is a real object. For the second example, you need to create instances of the class before you can make calls to it, because it only points to a memory location (which may be unassigned = a null reference):
ArmstrongMachine [] MyMachines = new ArmstrongMachine[10];
MyMachines[0] = new ArmstrongMachine();
MyMachines[0].AssignValues("AA", "ABC01236", 51000);
MyMachines[0].DisplayValues();

Array through parameter by reference affecting another array

CardDetails is a Structure.
public static void ParceIntricaciesJabber(ref CardDetails[] WhichArray)
{
WhichArray[0].ID = 50;
WhichArray[0].Type = "None";
}
In calling:
ParceIntricaciesJabber(ref OpponentCards);
After I call the function though, another Array called PlayerCards is affected in the exact same way as OpponentCards - despite being declared as two different arrays. They have the same number of elements and the same data Type, and that's it.
This probably should be obvious but i'm not seeing it. The code works in VB.NET. What am I doing wrong?
EDIT: Initialization Code:
public static class Module1{
public static CardDetails[] PlayerCards = new CardDetails[100];
public static CardDetails[] OpponentCards = new CardDetails[100];
}
And also when navigating to the Form
for (int n = 1; n <= 100; n++)
{
Module1.PlayerCards[n] = new CardDetails();
Module1.OpponentCards[n] = new CardDetails();
}
My guess is that you are sharing the reference to the arrays. Even though it is structs inside the array, the array itself is a reference type. You will need to post your array instantiation code to verify one way or the other though

Should I use a different object to lock for each property?

I have a class and its properties; the access to these properties is very frequently done by different threads.
It is more efficient use the same object (for the lock statement) for each property?
private readonly object padlock = new object();
private string name;
private int age;
public string Name
{
get
{
lock(padlock)
return name;
}
set
{
lock(padlock)
name = value;
}
}
public int Age
{
get
{
lock(padlock)
return age;
}
set
{
lock(padlock)
age = value;
}
}
Or to use a different object for each property?
private readonly object padlockName = new object();
private readonly object padlockAge = new object();
private string name;
private int age;
public string Name
{
get
{
lock(padlockName)
return name;
}
set
{
lock(padlockName)
name = value;
}
}
public int Age
{
get
{
lock(padlockAge)
return age;
}
set
{
lock(padlockAge)
age = value;
}
}
The second version makes any sense?
I hesitate to even answer the question you've asked, because I doubt that either of these locking patterns will ensure correctness in your application. They don't ensure that the object as a whole is kept in a consistent state - they just ensure that individual properties are not updated concurrently. To put it another way, you've implemented atomic reads and writes in a roundabout way.
For example, say you had an operation that would increment Age. If two different threads did that at once, the final result could be (Age + 1) or (Age + 2).
You should most likely remove locking from within the object, and have callers deal with concurrency issues as appropriate. One easy solution is to lock the entire object for the duration of their interaction with it. eg:
lock(myObj){
myObj.Age++;
myObj.Name = "Bill";
}
Update
To expand on my middle paragraph, the reason that running Age++ on two different threads could give different results is because the ++ operator is not atomic. It is roughly equivalent to this.
int temp = Age;
temp = temp + 1;
Age = temp;
If two threads ran the same thing, it could execute in order like this (for clarity I've changed names of the temp variables):
int temp1 = Age; //thread 1
int temp2 = Age; //thread 2
temp1 = temp1 + 1; //thread 1
temp2 = temp2 + 1; //thread 2
Age = temp1; //thread 1
Age = temp2; //thread 2
The purpose of locking is to ensure that one thread runs the entire read-increment-write sequence before the other thread does. But your locking scheme doesn't do that.
Note, this is highly dependent on how your object is accessed. The ultimate answer will be determined by measuring your performance in your environment and acting on that as well as the needs specific to your domain (although it seems like your concern here is corrupting the variables used to back the properties, not about accessing clusters of properties at the same time).
That said you have to balance out the following:
If you have one object to lock access to all the properties on the object, multiple threads accessing different properties will wait on each other to complete.
If you have one object per property, then accessing different properties will not cause locks to be waiting.
However, I'd say in this case it's moot as it seems like you're more worried about corruption of the values here.
Assignments and reads on a vast majority of types (excluding multi-field value types) are atomic, meaning you won't corrupt them.
That said, in the example above, where you have a read and write of a property of type string (a reference type) and an int, those operations are atomic and cannot be corrupted by reads/writes from multiple threads.

Categories