c# Accessing my array inside a class constructor - c#

I'm learning c# and have decided to try and create a functioning chance game, part by part.
I previously created a method that would create a random (yet likely inefficient) array of natural numbers that would not appear more than once.
However, as I try to piece together OOP I realised if I create multiple of these arrays they would be objects, thus should be created by a class.
I have the array created inside a constructor. Yet I cannot access this array from either within the constructor's class or in another class entirely.
class randomArray
{
Random rng = new Random();
protected int amountOfNumbers;
protected int rangeOfNumbers;
public randomArray(int amountOfNumbers, int rangeOfNumbers)
{
this.amountOfNumbers = amountOfNumbers;
this.rangeOfNumbers = rangeOfNumbers;
int[] randomizedArray = new int[amountOfNumbers];
for (int i = 0; i < amountOfNumbers; i++)
{
randomizedArray[i] = rng.Next(1, rangeOfNumbers + 1);
// A test to ensure that each new number generate is not
already part of the array.
for (int j = 0; j < i; j++)
{
while (randomizedArray[i] == randomizedArray[j])
{
randomizedArray[i] = rng.Next(1, rangeOfNumbers + 1);
j = 0;
}
if (randomizedArray[i] != randomizedArray[j])
continue;
}
}
}
public int RangeOfNumbers { get; set; }
public int AmountOfNumbers { get; set; }
I believe I'm failing to either understand the fundamentals of OOP or I am I failing to understand how to utilize classes.

Make your array a member of the actual class, ie property
public class randomArray
{
public int[] RandomizedArray { get; set; }
...
At about this time, you should probably have a read through this
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/class
https://learn.microsoft.com/en-us/dotnet/csharp/properties
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors
Update
public randomArray(int amountOfNumbers, int rangeOfNumbers)
{
...
RandomizedArray = new int[amountOfNumbers]
// do stuff here

Although the response of #TheGeneral contains the solution and points you towards more documentation for learning about OOP.
I think it is better to give an explanation why your code did not work.
Everything in OOP has a Scope (a certain "area" where it is available) which is, for most of the things in OOP, fenced of by the brackets.
In this instance the scope is based around the constructor, which causes the variables declared in the brackets to only be available inside the brackets. Except when you use an "outside" link like a class variable or property.
public class Example
{
// this is a class variable, this variable is now reachable from outside the class
// definition.
public int aClassVariable;
// this is a class property which because we added the get and set calls generate
// automatically an get and set method (internally)
public bool aClassProperty { get; set; }
public Example()
{
// to set the class variable and property you just give them a value.
aClassVariable = 42;
aClassProperty = true;
// this variable is not available outside the scope of this function,
// this is because you declared the variable inside this function.
// So the variable is only available inside this function as long as this
// function runs (or as it is called "is in scope").
int[] arr = new int[10];
}
}
Also pay attention about the differences between variables and properties, a variable is something every OOP language contains.
But the properties are actually an extension for the variables where the accessing and setting can be modified with a definition of the get and set method.
I would strongly suggest to read the documentation linked from the answer of TheGeneral because it contains far more information about the intricacies of OOP and C# itself.

Related

C# Private member shared by all class instances

I am currently working with C# using the Unity3D engine and have come upon the following problem:
I created a class that has two private references to instances of another class which it has to access. Once I create multiple instances of the class and set the references I found out that all instances were using the same variable. I realized this as I was destroying an instance and just before that set the two variables holding the references to null. Immediately after doing that all other instances were throwing NullReferenceExceptions because they were still trying to access the references. The referenced objects are fine, other scripts can still access them.
Here is some pseudo code illustrating the structure:
public class Character
{
// Character data
}
public class StatusEffect
{
private Character target;
private Character originator;
public void Init(Character _Target, Character _Originator)
{
target = _Target;
originator = _Originator;
}
public void Destroy()
{
target = null;
originator = null;
}
}
In the program it would be called like this:
StatusEffect effect = new StatusEffect();
effect.Init(player1, player2);
// Time goes by
effect.Destroy();
After calling Destroy() every StatusEffect's two references will be null.
This is not only an issue when destroying StatusEffects, but also when creating new ones. As soon as I touch the references from within a new instance all StatusEffects will reference the two Characters specified by the new StatusEffect.
I do not understand why or how I can fix this issue. Can someone enlighten me on this matter?
Cheers,
Valtaroth
EDIT:
Here is the real code as requested:
I have a container class holding several StatusEffects. As soon as it starts, it initializes all of them.
public class CElementTag
{
// ..Other data..
public float f_Duration; // Set in the editor
private CGladiator gl_target;
private CGladiator gl_originator;
private float f_currentDuration;
public CStatusEffect[] ar_statusEffects;
// Starts the effect of the element tag
public void StartEffect(CGladiator _Originator, CGladiator _Target)
{
gl_originator = _Originator;
gl_target = _Target;
f_currentDuration = f_Duration;
for(int i = 0; i < ar_statusEffects.Length; i++)
ar_statusEffects[i].Initialize(gl_originator, gl_target);
}
// Ends the effect of the element tag
public void EndEffect()
{
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null)
ar_statusEffects[i].Destroy();
}
}
// Called every update, returns true if the tag can be destroyed
public bool ActivateEffect()
{
f_currentDuration -= Time.deltaTime;
if(f_currentDuration <= 0.0f)
{
EndEffect();
return true;
}
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null && ar_statusEffects[i].Update())
RemoveStatusEffect(i);
}
return false;
}
// Removes expired status effects
private void RemoveStatusEffect(int _Index)
{
// Call destroy method
ar_statusEffects[_Index].Destroy();
// Remove effect from array
for(int i = _Index; i < ar_statusEffects.Length - 1; i++)
ar_statusEffects[i] = ar_statusEffects[i+1];
ar_statusEffects[ar_statusEffects.Length - 1] = null;
}
}
The actual StatusEffect class is holding the two references as well as some other data it needs to work. It has virtual methods because there are some classes inheriting from it.
public class CStatusEffect
{
// ..Necessary data..
// References
protected CGladiator gl_target;
protected CGladiator gl_originator;
virtual public void Initialize(CGladiator _Target, CGladiator _Originator)
{
gl_target = _Target;
gl_originator = _Originator;
// ..Initialize other necessary stuff..
}
virtual public void Destroy()
{
gl_target = null;
gl_originator = null;
// ..Tidy up other data..
}
virtual public bool Update()
{
// ..Modifying data of gl_target and gl_originator..
// Returns true as soon as the effect is supposed to end.
}
}
That should be all the relevant code concerning this problem.
EDIT2
#KeithPayne I have a static array of ElementTags defined in the editor and saved to xml. At the beginning of the program the static array is loading the xml and stores all element tags. When creating a new element tag to use I utilize this constructor:
// Receives a static tag as parameter
public CElementTag(CElementTag _Tag)
{
i_ID = _Tag.i_ID;
str_Name = _Tag.str_Name;
enum_Type = _Tag.enum_Type;
f_Duration = _Tag.f_Duration;
ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);
}
Do I have to use a different method to copy the array to the new tag? I thought Array.Copy would make a deep copy of the source array and stored it in the destination array. If it is in fact making a shallow copy, I understand where the problem is coming from now.
From Array.Copy Method (Array, Array, Int32):
If sourceArray and destinationArray are both reference-type arrays or
are both arrays of type Object, a shallow copy is performed. A shallow
copy of an Array is a new Array containing references to the same
elements as the original Array. The elements themselves or anything
referenced by the elements are not copied. In contrast, a deep copy of
an Array copies the elements and everything directly or indirectly
referenced by the elements.
Consider this fluent version of the StatusEffect class and its usage below:
public class StatusEffect
{
public Character Target { get; private set; }
public Character Originator { get; private set; }
public StatusEffect Init(Character target, Character originator)
{
Target = target.Clone()
Originator = originator.Clone();
return this;
}
//...
}
public CElementTag(CElementTag _Tag)
{
i_ID = _Tag.i_ID;
str_Name = _Tag.str_Name;
enum_Type = _Tag.enum_Type;
f_Duration = _Tag.f_Duration;
ar_statusEffects = _Tag.ar_statusEffects.Select(eff =>
new StatusEffect().Init(eff.Target, eff.Originator)).ToArray();
// ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
// Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);
}
Because you're passing in references to the objects via your Init() method, you're not actually "copying" the objects, just maintaining a reference to the same underlying objects in memory.
If you have multiple players with the same references to the same underlying objects, then changes made by player 1 will effect the objects being used by player 2.
Having said all that, you're not actually disposing the objects in your Destory method. Just setting the local instance references to Null which shouldn't affect any other instances of StatusEffects. Are you sure something else isn't disposing the objects, or that you haven't properly init'd your other instances.
If you do want to take a full copy of the passed in objects, take a look at the ICloneable interface. It looks like you want to pass in a copy of the objects into each Player.
public class Character : ICloneable
{
// Character data
//Implement Clone Method
}
public class StatusEffect
{
private Character target;
private Character originator;
public void Init(Character _Target, Character _Originator)
{
target = _Target.Clone()
originator = _Originator.Clone();
}
The fields aren't shared(static) among other instances. So calling target = null; in Destroy() won't affect other instances.
StatusEffect effect1 = new StatusEffect();
effect1.Init(player1, player2);
StatusEffect effect2 = new StatusEffect();
effect2.Init(player1, player2);
// Time goes by
effect2.Destroy();
// Some more time goes by
// accessing effect1.target won't give a `NullReferenceException` here unless player1 was null before passed to the init.
effect1.Destroy();
I think you did forget the Init(..) on the other instances. Every time you create an instance of StatusEffect, you need to call Init(...).
Update:
This line will clear the reference to the effect, but you never recreate it:
ar_statusEffects[ar_statusEffects.Length - 1] = null;
so the next time you call ar_statusEffects[x].Update() or Initialize() etc it will throw a NullReferenceException
If you want to clear out effects within you array, you could create an Enable bool in the effect, this way you only have to set/reset it.
for(int i = 0; i < ar_statusEffects.Length; i++)
if(ar_statusEffects[i].IsEnabled)
ar_statusEffects[i].Update();
Why don't you use a List instead? Arrays will be faster as long you don't have to shuffle in it. (like circulair buffers etc)
Thanks to Keith Payne I figured out where the problem was. I was creating a deep copy of CElementTag, but not of my ar_statusEffects array. I wrongly assumed Array.Copy was creating a deep copy of an array when it actually was not.
I implemented the IClonable interface for my CStatusEffect and use the Clone() method to create a true deep copy for each member of the static array and add it to the new tags ar_statusEffects array. This way I have seperate instances of the effects instead of references to the same static effect.
Thanks to everyone, especially Keith Payne, for their help and support!

is it possible to create a public method that generates an unknown number of private instance variables in C#?

Basically I am trying to implement my own array class, and I was wondering if creating a public method that generates an unknown number of private instance variables was the way to go? Something like:
public class myArray {
public myArray(int length) {
for(int i = 0; i < length; i++) {
int component+i;
}
}
int component(int indexOfComponent) {
return component+indexOfComponent;
}
}
I know the the line of code inside that for loop makes no sense. But I just thought I would illustrate what I was talking about. What would result from creating an object from the myArray class with 3 as the constructor parameter would be:
public class myArray {
private int component1;
private int component2;
private int component3;
public myArray(int length) {
for(int i = 0; i < length; i++) {
int component+i;
}
int component(int indexOfComponent) {
return component+indexOfComponent;
}
}
}
And I know those variables would only exist inside the for loop, but that is the best way I can exemplify what I am trying to do. Is this even the way to go if I am trying to implement my own array class?
Also; there's one more thing about this that I think may deserve a separate question but it's the whole problem with naming variables dynamically with a for loop.
Basically I am trying to implement my own array class
I'd urge you not to do that.
I was wondering if creating a public method that generates an unknown number of private instance variables was the way to go
No. The variables need to known at compile-time.
The "way to go" is to use an array or another existing collection type.
Fundamentally you can't implement arrays directly in C#. Arrays and strings are the only objects where the size of an instance varies from object to object. For everything else, the layout is the same for every object.
(As mentioned in comments, you could dynamically create a new type for each instance using Reflection.Emit or something similar, but you really really don't want to do that.)

Link Two Properties/Variables

Let me explain my situation. I have a program who reads an external connection and gives me an array of integers (or booleans). Those inputs should feed an object that has some properties (X, Y, Z, for example). So, if a read a value on array, i should write those values in the properties. Is there a way to pass those values by ref (for example) ? Thinking logically , the best way way would be pointers (property X pointing to array[0]), but these aren't very unclear to me.
I can create a way to look for changes in array (but is a very large array, +60000), then update my object. But i think this would be a bad ideia.
Sorry if i wrote any crap, i'm just starting on C#.
Some pseudo code to help.
class obj
{
int X {get; set;}
public obj(ref int x)
{
X = x;
}
}
class main
{
void main()
{
int a;
obj test = new obj(ref a);
}
}
So if: a = 10, obj.X = 10 too.
public class MyClass
{
private int[] backingArray;
public int X
{
get
{
if (backingArray == null)
return -1;
else
return backingArray[0];
}
}
public MyClass(int[] array)
{
if (array.Length > 0)
backingArray = array;
}
}
class Main
{
void Main()
{
int[] array = new int[] { 2 };
MyClass test = new MyClass(array);
array[0] = 6;
Console.WriteLine(test.X);//prints 6
}
}
Of course this only works with reference types (arrays are reference types). If you wanted to do this whole thing with a value type, you'd need to "wrap" it in some reference type. You can use a class such as the following to wrap anything if you don't have anything convenient.
public class Wrapper<T>
{
public T Value { get; set; }
}
It's not possible to use ref in the manor that you've shown in the OP. You wouldn't be able to store the value that was passed by reference. If you could, then you could end up passing some value on the stack and then having the created object that holds the reference living longer than the item on the stack. If that happened you would end up with a reference it a location in memory that no longer holds the variable you intended. This was somewhat of a gotcha in C++ that the designers of C# went out of their way to ensure can't happen (at least not without a lot of work).

Creating class instances at run-time and initializing simultaneously

I am attempting following code to create multiple instances of a class at run-time and want to initialize also, but it is giving error:
A local variable named 'inum' cannot be declared in this scope because
it would give a different meaning to 'inum', which is already used in
a 'parent or current' scope to denote something else.
public class MyClass
{
static int i=0;
class A
{
public A()
{
}
}
public static void Run()
{
string inum = "i";
for (int j=1;j<=5;j++)
{
inum = inum + j.ToString();
//Initialize Instance
A inum = new A();
}
}
}
You appear to be trying to use variable names "dynamically". That doesn't work in C#, and you should change how you think about variables. If you want to create several instances, declare an array:
public class MyClass
{
static A[] instances;
class A
{
public A()
{
}
}
public static void Run()
{
instances = new A[5];
for (int j=0;j<5;j++)
{
instances[j] = new A();
}
}
}
You cannot have dynamic variable in c#. The append you are trying is appending the value not the variable pointer.
rather use this way
Dictionary<int, A> inum = new Dictionary<int, A>();
for (int j=1;j<=5;j++)
{
//Initialize Instance and add to dictionary
inum.Add(j, new A());
}
You can get them by key name. There are several other way to store instances as collection
I'm not a C# programmer by any stretch of the imagination, but by the rules of Java and any other similarly syntaxed language I know anything about, what you are doing is attempting to redeclare 'inum' with a new type, after it has been declared as a string in the same scope.
The other point is that even if this were not the case, you are not creating multiple instances but filling the same variable with a new instance 5 times, which would only result in one instance (the last one).
From quickly reading a C# tutorial I think this is something like what you want. I'm not sure what you were trying to do with the 'inum' variable so it is gone, as is static variable 'i':
public class MyClass
{
class A
{
public A()
{
}
}
public static void Run()
{
// Declare array to hold instances
A[] instances;
// instances is now five elements long
instances = new A[5];
for (int j=0;j<5;j++)
{
//Initialize Instance
instances[j] = new A();
}
}
}
That should result in an array of 5 objects called 'instances' in the scope of the Run method - you may want this in the scope of the class itself, possibly as a static property.
As a side note, it's good practice to start at 0, not 1, for operations like this (with the var 'j') and the above code reflects this.
you cannot call the variable of type A "inum" (there exists already one called like that)
you have to give it another name like:
A anyOtherName = new A();
try to name the variable A with different name
A objA = new A();

Anonymous classes, temporary data, and collections of anonymous classes

I'm new to anonymous classes, and today I think I ran into the first case where I felt like I could really use them. I'm writing a method that would benefit from storing temporary data inside of a class, and since that class doesn't have any meaning outside of that method, using an anonymous class sure made sense to me (at least at the time it did).
After starting on the coding, it sure seemed like I was going to have to make some concessions. I like to put assign things like calculations to temporary variables, so that during debugging I can verify bits of calculations at a time in logical chunks. Then I want to assign something simpler to the final value. This value would be in the anonymous class.
The problem is that in order to implement my code with anonymous classes concisely, I'd like to use LINQ. The problem here is that I don't think you can do such temporary calculations inside of the statement. or can you?
Here is a contrived example of what I want to do:
namespace AnonymousClassTest
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
ObservableCollection<RectanglePoints> Points { get; set; }
public class RectanglePoints
{
public Point UL { get; set; }
public Point UR { get; set; }
public Point LL { get; set; }
public Point LR { get; set; }
}
public class DontWantThis
{
public double Width { get; set; }
public double Height { get; set; }
}
private Dictionary<string,string> properties = new Dictionary<string,string>();
private Dictionary<string,double> scaling_factors = new Dictionary<string,double>();
private void Sample()
{
// not possible to do temp variables, so need to have
// longer, more unreadable assignments
var widths_and_heights = from rp in Points
select new
{
Width = (rp.UR.X - rp.UL.X) * scaling_factors[properties["dummy"]],
Height = (rp.LL.Y - rp.UL.Y) * scaling_factors[properties["yummy"]]
};
// or do it in a for loop -- but then you have to use a concrete
// class to deal with the Width and Height storage
List<DontWantThis> other_widths_and_heights = new List<DontWantThis>();
foreach( RectanglePoints rp in Points) {
double base_width = rp.UR.X - rp.UL.X;
double width_scaling_factor = scaling_factors[properties["dummy"]];
double base_height = rp.LL.Y - rp.UL.Y;
double height_scaling_factor = scaling_factors[properties["yummy"]];
other_widths_and_heights.Add( new DontWantThis
{
Width=base_width * width_scaling_factor,
Height=base_height * height_scaling_factor
});
}
// now we want to use the anonymous class, or concrete class, in the same function
foreach( var wah in widths_and_heights)
Console.WriteLine( String.Format( "{0} {1}", wah.Width, wah.Height));
foreach( DontWantThis dwt in other_widths_and_heights)
Console.WriteLine( String.Format( "{0} {1}", dwt.Width, dwt.Height));
}
public Window1()
{
InitializeComponent();
Points = new ObservableCollection<RectanglePoints>();
Random rand = new Random();
for( int i=0; i<10; i++) {
Points.Add( new RectanglePoints { UL=new Point { X=rand.Next(), Y=rand.Next() },
UR=new Point { X=rand.Next(), Y=rand.Next() },
LL=new Point { X=rand.Next(), Y=rand.Next() },
LR=new Point { X=rand.Next(), Y=rand.Next() }
} );
}
Sample();
}
}
}
NOTE: don't try to run this unless you actually add the keys to the Dictionary :)
The creation of the anonymous class in LINQ is awesome, but forces me to do the calculation in one line. Imagine that the calc is way longer than what I've shown. But it is similar in that I will do some Dictionary lookups to get specific values. Debugging could be painful.
The usage of a concrete class gets around this problem of using temporary variables, but then I can't do everything concisely. Yes, I realize that I'm being a little contradictory in saying that I'm looking for conciseness, while asking to be able to save temp variables in my LINQ statement.
I was starting to try to create an anonymous class when looping over Points, but soon realized that I had no way to store it! You can't use a List because that just loses the entire anonymity of the class.
Can anyone suggest a way to achieve what I'm looking for? Or some middle ground? I've read a few other questions here on StackOverflow, but none of them are exactly the same as mine.
Assuming I understand you correctly, the problem is that you have to set all the properties in a single expression. That's definitely the case with anonymous types.
However, you don't have to do it all inline in that expression. I would suggest that if your properties are based on complex expressions, you break those expressions out into helper methods:
var complex = new {
First = ComputeFirstValue(x, y),
Second = ComputeSecondValue(a, b)
...
};
This has the additional potential benefit that you can unit test each of the helper methods individually, if you're a fan of white-box testing (I am).
This isn't going to avoid there being in one big anonymous type initializer expression, but it means the work will be broken up.
Anonymous classes are really intended to simplify stuff dealing with lambdas, not least LINQ. What you're trying to do sounds much more suited to a nested private class. That way, only your class really knows about your temp class. Trying to muck around with anonymous classes seems only to complicate your code.

Categories