Using An Array Inside A Class - c#

I am trying to initialize an array that is inside a class.
I am getting the "object reference is not set to an instance of an object" error.
Here's my NPC class:
namespace EngineTest
{
public class npcs
{
public int tileX, tileY, layerZ;
public int textureX, textureY;
public string ID;
public string state;
public int direction; //0 = south, 1= west, 2 = north, 3= east
public int moveLimitTimer;
public int animationCurrentFrame;
public int animationResetTimer;
public pathPotentials[, ,] pathPotential; (this is the array)
}
}
Here is the pathPotentials Class
namespace EngineTest
{
public class npcs
{
public int tileX, tileY, layerZ;
public int textureX, textureY;
public string ID;
public string state;
public int direction; //0 = south, 1= west, 2 = north, 3= east
public int moveLimitTimer;
public int animationCurrentFrame;
public int animationResetTimer;
public pathPotentials[, ,] pathPotential = new pathPotentials[Program.newMapWidth, Program.newMapHeight, Program.newMapLayers];
}
}
I tried to initialize it by this code:
for (z = 0; z < Program.newMapLayers; z++)
{
for (x = 0; x < Program.newMapWidth; x++)
{
for (y = 0; y < Program.newMapHeight; y++)
{
if(Program.tileNpcs[x, y, z].npcs.Count > 0)
{
Program.tileNpcs[x, y, z].npcs[0].pathPotential[Program.newMapWidth, Program.newMapHeight, Program.newMapLayers] = new pathPotentials();
}
}
}
}
But it doesn't work. What should I do?
Thanks in advance.

In C# (and a lot of programming languages of this type), arrays have a fixed length. In C#, arrays are stored as an object, with a set of values. Assigning to an element in an array is like altering a field of an object - you need to define the array explicitly first. If you don't define it explicitly, C# doesn't know how much memory to assign the array, which can cause a lot of problems when structuring memory.
You declare a 3-dimensional array, but you don't define it:
public pathPotentials[, ,] pathPotential;
What you need is something like this:
public pathPotentials[, ,] pathPotential = new pathPotentials[Program.newMapWidth, Program.newMapHeight, Program.newMapLayers];
This tells C# exactly how big to make your array.
However, this does not allow you to change the size of the array once it is declared (at least without clearing it by redefining it). If you need the size to change at runtime, then C# provides a class List, which takes a generic parameter (which in this case is fairly complex, for a 3D grid). You can declare something like this with Lists like so:
public List<List<List<pathPotentials>>> pathPotential = new List<List<List<pathPotentials>>>();
This gives you a nested list of lists of lists. The innermost list might be z, the outermost x. To get data from this, you can specify an inex, but you can no longer use [x,y,z] as the notation, and must instead use [x][y][z], as you are accessing a list to get another list item, and then accessing that list to get a second list item, and then accessing that one to get your object.
Hopefully, this has helped you to understand what went wrong, why your code doesn't work, and how you might fix it.

the code is bound to give you the error, since before initializing you are referencing a particular item of array. instead of your statement:
Program.tileNpcs[x, y, z].npcs[i].pathPotential[Program.newMapWidth, Program.newMapHeight, Program.newMapLayers] = new pathPotentials();
You should have it this way:
Program.tileNpcs[x, y, z].npcs[i].pathPotential = new pathPotentials[Program.newMapWidth, Program.newMapHeight, Program.newMapLayers];
Hope that helps..

Related

How to access variables inside an object?

I am creating an algorithm to fill up a train with animals based on their size and type.
Imagine an animal object in an animal class with a type and size.
/* 0 = Carnivore, Carnivores will eat other animals which are smaller or the same size.
* 1 = Herbivore
* Animal sizes 1, 3, 5 are currently available.
* A trainwagon can fit a maximum of 10 points. The wagon needs to filled optimally.
* A new wagon is added if there are still animals which need to board the train.
*/
public Animal(int type, int size)
{
this.type = type;
this.size = size;
}
I need the value of an animal to sort them. So, I created an override ToString() method to get the value.
public override string ToString()
{
string animalInformation = type.ToString() + size.ToString();
return animalInformation.ToString();
}
I currently solved it by separating the characters of the string and converting them back to integers.
int animalType = Convert.ToString(animalInformation[0]);
int animalSize = Convert.ToString(animalInformation[1]);
My question is: Is there another technique to access the variables in the animal object, because the double conversion impacts the performance of my algorithm in a unneccesary way.
Take another look at your constructor:
public Animal(int type, int size)
{
this.type = type;
this.size = size;
}
This means that type and size are data members of your Animal class, which means that any instance of Animal has a type or a size. this.type is not a variable, but rather a data member of an object, which is similar to a variable due to its changeability, but it's an inherent attribute of an object. If you do something like
Animal animal = new Animal(1, 1);
and then you cannot reach animal.type, that means that animal.type is not public, but rather private or protected. You would be able to reach it if it were public. However, don't change it to public, it's good if you protect your fields from some problematic accesses I'm not describing at this point. Instead, you can define getters, like
public int getType() {
return this.type;
}
public int getSize() {
return this.size;
}
or some readonly properties and get the values by these.
Unless there is some detail not evident from the question, you should just create properties for the fields, i.e.
public readonly struct Animal
{
public int Type { get; }
public int Size { get; }
public Animal(int type, int size)
{
Type = type;
Size = size;
}
}
Sorting can be done with linq. 'ThenBy(...)' is only needed if you need to sort by both properties:
var sortedAnimals = animals.OrderBy(animal => animal.Type).ThenBy(animal => animal.Size);
As mentioned in the comments, if you only want to allow some values for type and size, you should probably use enums. Or at least validate the arguments and throw an exception if the validation fails.

Is there a polymorphic 2D collection type that includes arrays in c#?

So let's say I have a helper class which contains methods that manipulate a collection:
public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
{
int total = 0;
for(int i=0; i < graph.Edges.Count; i++)
{
int startRemDeg = graph.Edges[i].Start.RemDeg;
int endRemDeg = graph.Edges[i].End.RemDeg;
distArr[startRemDeg,endRemDeg]++;
distArr[endRemDeg, startRemDeg]++;
total = total+2;
}
for(int i=0; i < distArr.GetLength(0); i++)
{
for(int j=0; j < distArr.GetLength(1); j++)
{
distArr[i,j] /= total;
}
}
}
How can I change the code to allow the collection that is passed in to either be an array or one of my own collection classes?
The trouble is, the collection that is passed in must be 2-dimensional. There isn't an interface that I can implement in my own collection classes that arrays also implement.
I want to be able to reuse the code for both cases and avoid introducing lots of ugly conditional logic. I also need to avoid allocating memory so making some kind of wrapper class for arrays isn't acceptable. I also want to avoid using lists within lists as its so much simpler to work with normal 2d arrays and lists allocate too much memory for my purposes. It seems like this should be possible with indexers or something. Like is there a way to declare that "distArr" must be any type with an indexer that takes two arguments etc.?
There is no such interface. So you need to make your own, for instance:
public interface IMatrix<T>
{
int Rows { get; }
int Columns { get; }
ref T this[int row, int column] { get; }
}
and additionally of implementing it in your collection classes, create adapter for arrays (Adapter Pattern).
I know, I know, you said
I also need to avoid allocating memory so making some kind of wrapper class for arrays isn't acceptable.
I don't think a tiny short lived GC3 generation wrapper object will hurt your system, but anyway, the heap allocation can be avoided by implementing the wrapper as a struct:
public struct ArrayMatrix<T> : IMatrix<T>
{
readonly T[,] source;
public ArrayMatrix(T[,] source) => this.source = source;
public int Rows => source.GetLength(0);
public int Columns => source.GetLength(1);
public ref T this[int row, int column] => ref source[row, column];
}
and making your method generic (to avoid boxing of the struct):
public static void RemainingDegreeDistribution<TMatrix>(IGraph graph, TMatrix distArr)
where TMatrix : IMatrix<float>
{
int total = 0;
for (int i = 0; i < graph.Edges.Count; i++)
{
int startRemDeg = graph.Edges[i].Start.RemDeg;
int endRemDeg = graph.Edges[i].End.RemDeg;
distArr[startRemDeg, endRemDeg]++;
distArr[endRemDeg, startRemDeg]++;
total = total + 2;
}
for (int i = 0; i < distArr.Rows; i++)
{
for (int j = 0; j < distArr.Columns; j++)
{
distArr[i, j] /= total;
}
}
}
To make it easier to be used with arrays, you could add a helper method:
public static class ArrayMatrix
{
public static ArrayMatrix<T> ToMatrix<T>(this T[,] source) => new ArrayMatrix<T>(source);
}
and even provide overload of your method with array argument:
public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
=> RemainingDegreeDistribution(graph, distArr.ToMatrix());
If you need to represent point in 2D space i suggesto you to use Point data structure.
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.point?view=netframework-4.7.2
Try overloading if you also would pass an array of coordinates and points :
public static Method ( float[,] coordinates )
{
//generate array of Points starting from coordinates , points.Add ( new Point(coordinate[i,j]) )
}
public static Method ( Point[] points)
{
//actual logic
}

Best way to represent sets of 3 values

Assume that I have 100 sets of 3 values. first value is time, second value is x position and 3rd value is y position. this is going to be the xy position of a point over 100 seconds for example.
I have a PHP background. in PHP I would do it with a 3D associative array like this :
position["time"]["x"]["y"]
so I can access x,y values at a certain time. How would you do this in c#? I think generics like list and dictionary would do that. but I don't know how to implement key values for a 3D set of data.
In C# there is types concept, you would need to create a concrete custom type either struct (value type )or class (reference type)
Value Types
Refrence Types
You can create a new type in this case i am creating class which would be like:
public class Position
{
public DateTime Time {get;set;}
public int X {get;set;}
public int Y {get;set;}
}
Now at some point you would have a instance of class position:
Position postion = new Position(); // object created
positon.Time = DateTime.Now;
position.X = 1;
position.Y =0;
and the same way you would get the values back from it :
DateTime time = position.Time;
int positionX = position.X;
int positionY = position.Y;
I would suggest to read basics of type from MSDN here
and for sets part, we have Framework provided collections in C# which includes Array,List which can be used to hold multiple objects of Position.
Hope It helps!
It looks like you want to access an x/y position at a given time. You might consider a combination of the other answers along with a dictionary.
Define a simple struct which holds x & y positions. It is important that this object is immutable.
public struct Position
{
public int X { get; }
public int Y { get; }
public Position(int x, int y)
{
this.X = x;
this.Y = y;
}
}
Now you can store these in a dictionary with (perhaps) DateTime as the key.
Dictionary<DateTime, Position> positions = new Dictionary<DateTime, Position>();
positions.Add(new DateTime(2017,3,29,10,0,0), new Position(10,10));
And you can read your position like
var pos = positions[new DateTime(2017,3,29,10,0,0)];
Console.WriteLine("{0}:{1}",pos.X,pos.Y);
A neat little addition to this is that if, for example, you are getting a list of these object you wish to lookup by time you can easily turn them into a dictionary. Say your get a list of these (from other answer):
public class PositionEntity
{
public DateTime Time {get;set;}
public int X {get;set;}
public int Y {get;set;}
}
As a list entities you can do this:
IEnumerable<PositionEntity> entities = .... loaded from somewhere
var dict = entities.ToDictionary(k => k.Time, v => new Position(v.X,v.Y));
I suggest defining an immutable type for this purpose and use a dictionary to store values since an object can be in one place at a specific time.
public class Position
{
public Position(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
}
use it like this:
var data = new Dictionary<TimeSpan, Position>();
//add data in two different ways
data.Add(TimeSpan.FromMilliseconds(10), new Position(0.1, 1));
data[TimeSpan.FromMilliseconds(15)] = new Position(10, 15);
//accessing data
var pos = data[TimeSpan.FromMilliseconds(10)];
//check if data exist for specific time
if (data.ContainsKey(TimeSpan.FromMilliseconds(15)))
{
//do what you want
}
You can use the Tuple class (See Tuple class on msdn)
Tuple.Create("time", "x", "y"); //creates a Tuple with 3 elements, aka triple
A simple solution might be to use a Tuple, if this is suitable for your needs, e.g.
Example:
var tuple = Tuple.Create(someBytes, moreBytes, myString);
You can access the values using tuple.Item1, tuple.Item2, and tuple.Item3.
You can of course also use multiple Tuples if you require this, e.g.
Example
var list = new List<Tuple<byte, byte, string>> {
tuple,
anotherTuple,
thirdTuple,
etc
};
As others have mentioned though, if you're referencing "like" data, you should create a class instead.

Why has to be size of dynamically-allocated array a static field?

I have a dummy class where I am testing arrays. I've noticed that when I want to dynamically allocate size of array at runtime, fields that indicate this size have to be static. I know I should probably use collections for this kind of code, but I'm more interested why do these fields have to be static? Is there any particular reason behind this?
class Foo
{
private static int x;
private static int y;
private int[,] bar = new int[ x, y ];
public Foo( int a, int b )
{
x = a;
y = b;
}
}
They don't really have to be static - it's just that you can't refer to other instance variables within instance variable initializers. In other words, it's a bit like this:
class Foo
{
private int x;
private int y = x; // Invalid
}
From section 10.5.5.2 of the C# 3 spec:
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.
I suspect you really want something like this:
class Foo
{
private int x;
private int y;
private int[,] bar;
public Foo( int a, int b )
{
x = a;
y = b;
bar = new int[x, y];
}
}
Of course you don't really need x and y at all - they're just convenient to keep each dimension of the array. You could also use bar.GetLength(0) and bar.GetLength(1) to get the two lengths, but that's not terribly pleasant.
You might want to rename x and y to width and height though, or something similar :)
The example shown of 'Foo will never have the array 'bar be anything but an an array of size [0,0] : it's instantiation occurs before you call the class constructor.
Try this :
public class Foo2
{
private int[,] bar;
public Foo2(int a, int b)
{
bar = new int[a,b];
}
}
That will give you an array of size [a,b] without use of 'static.

How to wrap an int[,] with something like a ReadOnlyCollection?

Seems like I can't do this:
private int[,] _table = new int[9, 9];
private ReadOnlyCollection<int[,]> _tableReadOnly = new ReadOnlyCollection<int[,]>(_table);
My idea is to have a property that let's the user read _table, but I don't want to let them change it, so I thought I could use ReadOnlyCollection for the matter.
The ReadOnlyCollection is a one dimensional collection. You could make a ReadOnlyCollection<ReadOnlyCollection<int>>, or make your own two dimensional wrapper class, something like:
public class ReadOnlyMatrix<T> {
private T[,] _data;
public ReadOnlyMatrix(T[,] data) {
_data = data;
}
public T this[int x, int y] {
get {
return _data[x, y];
}
}
}
The problem is you're trying to wrap a 2D mutable structure with a 1D read only structure. You'll need several levels of nesting to accomplish this.
ReadOnlyCollection<ReadOnlyCollection<int>>
The downside to this approach though is that it will essentially force you to have the entire table in memory twice. ReadOnlyCollection<T> requires a List<T> as the sole constructor argument. So you will end up copying each one of your rows into a new List<int>.
Another way to accomplish this though is to use a property indexer to return the value directly without allowing for mutation.
public int this[int i, int j] {
get { return _table[i,j]; }
}
This allows consumers to read the data without every having to mutate it.
You could do something like:
public class ReadOnly2DArray<T>
{
T[,] _array;
public ReadOnly2DArray(T[,] arrayToWrap)
{
_array = arrayToWrap;
}
public T this[int x, int y]
{
get { return _array[x, y]; }
}
}
possibly adding other methods of the Array class (Length property, GetLength method, ...) if you need them.
You'd then use it something like:
int[,] a = new int[2, 2];
ReadOnly2DArray<int> wrapper = new ReadOnly2DArray<int>(a);
int value = wrapper[0, 0]; // Can read values
//wrapper[0, 0] = value; // Won't compile
I'm not entirely sure I understand the direction you were taking, but based on your description of what you're trying to accomplish, it seems to me that you can just do the following:
private int[,] _table = new int[9, 9];
public int[,] Table
{
get
{
return _table;
}
}

Categories