public class CubicMatrix<Object?>
{
private int width;
private int height;
private int depth;
private Object[, ,] matrix;
public CubicMatrix(int inWidth, int inHeight, int inDepth)
{
width = inWidth;
height = inHeight;
depth = inDepth;
matrix = new Object[inWidth, inHeight, inDepth];
}
public void Add(Object toAdd, int x, int y, int z)
{
matrix[x, y, z] = toAdd;
}
public void Remove(int x, int y, int z)
{
matrix[x, y, z] = null;
}
public void Remove(Object toRemove)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
for (int z = 0; z < depth; z++)
{
Object value = matrix[x, y, z];
bool match = value.Equals(toRemove);
if (match == false)
{
continue;
}
matrix[x, y, z] = null;
}
}
}
}
public IEnumerable<Object> Values
{
get
{
LinkedList<Object> allValues = new LinkedList<Object>();
foreach (Object entry in matrix)
{
allValues.AddLast(entry);
}
return allValues.AsEnumerable<Object>();
}
}
public Object this[int x, int y, int z]
{
get
{
return matrix[x, y, z];
}
}
public IEnumerable<Object> RangeInclusive(int x1, int x2, int y1, int y2, int z1, int z2)
{
LinkedList<Object> list = new LinkedList<object>();
for (int a = x1; a <= x2; a++)
{
for (int b = y1; b <= y2; b++)
{
for (int c = z1; c <= z2; c++)
{
Object toAdd = matrix[a, b, c];
list.AddLast(toAdd);
}
}
}
return list.AsEnumerable<Object>();
}
public bool Available(int x, int y, int z)
{
Object toCheck = matrix[x, y, z];
if (toCheck != null)
{
return false;
}
return true;
}
}
I've created a Cubic Matrix class in C# to store items in 3 dimensions. I need to be able to add and remove items which is why I'm using Object? (I've been led to understand that you can't use nullable generics ie. T?). However this approach gnerates an error
Type parameter declaration must be an identifier not a type
If i don't use Object? though and just use Object or T i get this error instead
Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.
What's the correct syntax and approach to use in this case?
If you want to restrict your generic type to objects only - i.e. no structs or simple types - you can add the where clause
public class CubicMatrix<T> where T : class
These means that T can only be a class.
When returning default(T) instead (as the error you are getting suggests), reference types will return null, numeric types will return 0, your custom classes will return null and nullables will return System.Nullable<T>. More about this in default Keyword in Generic Code (C# Programming Guide)
on MSDN.
I think you want to use the generic parameter T. You're making a simple container class, so allowing any generic parameter makes sense, whether it's nullable or not. To fix the error, just do what it says and use default(T) instead of null.
The error is because T could be a class or a struct, and structs can't be null. Therefore assigning a variable with type T to null is invalid. default(T) is null when T is a class and default values when T is a struct.
Related
I have this code:
public void myMethod()
{
int a = 10;
int b = 20;
Func<int, int, int> multiplyDelegate;
multiplyDelegate = Multiply;
multiplyDelegate += Multiply2;
Console.WriteLine(multiplyDelegate(a,b));
}
public int Multiply(int x, int y)
{
return x * y;
}
public int Multiply2(int x, int y)
{
return x * y + 10;
}
By running myMethod, I expect the console to show the returns from both methods "Multiply" and "Multiply2" but only the return from the method "Multiply2" is shown. Have I done something wrong here or have I misunderstood the concept of delegates? From what I've learned a delegate is an array of references to methods.
From Using Delegates (C# Programming Guide):
If the delegate has a return value and/or out parameters, it returns
the return value and parameters of the last method invoked.
You are right delegate can store methods and invoke multiple methods at once. It will return the last one except if you explicitly Invoke them.
Using your code, here is an example of explicite Invoke for all of your collection of methods.
var results = multiplyDelegate.GetInvocationList().Select(x => (int)x.DynamicInvoke(10, 20));
foreach (var result in results)
Console.WriteLine(result);
EDIT :
This will work for function Func and not Action. Here is an example supposing it's an Action
foreach (Delegate action in multiplyDelegate.GetInvocationList())
{
action.DynamicInvoke(10, 20);
// Do Something
}
This second example work for Func as well.
I don't have any official sources for this, but I think what is happening is that you can't return two values from one delegate call. Therefore, the last value returned is used.
Although only the last return value is used, the two methods are indeed executed. We can prove this by printing some stuff before we return:
public int Multiply(int x, int y)
{
Console.WriteLine("Hello1");
return x * y;
}
public int Multiply2(int x, int y)
{
Console.WriteLine("Hello2");
return x * y + 10;
}
Both Hello1 and Hello2 are printed.
Only one object can be returned and since Multiple2 is the last to execute it get's outputted in the console.
There isnt a way to change that.
You could do:
public void myMethod()
{
int a = 10;
int b = 20;
Action<int, int> multiplyDelegate;
multiplyDelegate = Multiply;
multiplyDelegate += Multiply2;
multiplyDelegate(10, 20);
Console.Read();
}
public void Multiply(int x, int y)
{
Console.WriteLine(x * 2);
}
public void Multiply2(int x, int y)
{
Console.WriteLine(x * y + 10);
}
I had this question too and test several things like another way of setting method to the delegate but finally only usable way is to write another line after each set:
public void myMethod()
{
int a = 10;
int b = 20;
Func<int, int, int> multiplyDelegate;
multiplyDelegate = Multiply;
Console.WriteLine(multiplyDelegate(a,b));
multiplyDelegate += Multiply2;
Console.WriteLine(multiplyDelegate(a,b));
}
public int Multiply(int x, int y)
{
return x * y;
}
public int Multiply2(int x, int y)
{
return x * y + 10;
}
I have this code:
public void myMethod()
{
int a = 10;
int b = 20;
Func<int, int, int> multiplyDelegate;
multiplyDelegate = Multiply;
multiplyDelegate += Multiply2;
Console.WriteLine(multiplyDelegate(a,b));
}
public int Multiply(int x, int y)
{
return x * y;
}
public int Multiply2(int x, int y)
{
return x * y + 10;
}
By running myMethod, I expect the console to show the returns from both methods "Multiply" and "Multiply2" but only the return from the method "Multiply2" is shown. Have I done something wrong here or have I misunderstood the concept of delegates? From what I've learned a delegate is an array of references to methods.
From Using Delegates (C# Programming Guide):
If the delegate has a return value and/or out parameters, it returns
the return value and parameters of the last method invoked.
You are right delegate can store methods and invoke multiple methods at once. It will return the last one except if you explicitly Invoke them.
Using your code, here is an example of explicite Invoke for all of your collection of methods.
var results = multiplyDelegate.GetInvocationList().Select(x => (int)x.DynamicInvoke(10, 20));
foreach (var result in results)
Console.WriteLine(result);
EDIT :
This will work for function Func and not Action. Here is an example supposing it's an Action
foreach (Delegate action in multiplyDelegate.GetInvocationList())
{
action.DynamicInvoke(10, 20);
// Do Something
}
This second example work for Func as well.
I don't have any official sources for this, but I think what is happening is that you can't return two values from one delegate call. Therefore, the last value returned is used.
Although only the last return value is used, the two methods are indeed executed. We can prove this by printing some stuff before we return:
public int Multiply(int x, int y)
{
Console.WriteLine("Hello1");
return x * y;
}
public int Multiply2(int x, int y)
{
Console.WriteLine("Hello2");
return x * y + 10;
}
Both Hello1 and Hello2 are printed.
Only one object can be returned and since Multiple2 is the last to execute it get's outputted in the console.
There isnt a way to change that.
You could do:
public void myMethod()
{
int a = 10;
int b = 20;
Action<int, int> multiplyDelegate;
multiplyDelegate = Multiply;
multiplyDelegate += Multiply2;
multiplyDelegate(10, 20);
Console.Read();
}
public void Multiply(int x, int y)
{
Console.WriteLine(x * 2);
}
public void Multiply2(int x, int y)
{
Console.WriteLine(x * y + 10);
}
I had this question too and test several things like another way of setting method to the delegate but finally only usable way is to write another line after each set:
public void myMethod()
{
int a = 10;
int b = 20;
Func<int, int, int> multiplyDelegate;
multiplyDelegate = Multiply;
Console.WriteLine(multiplyDelegate(a,b));
multiplyDelegate += Multiply2;
Console.WriteLine(multiplyDelegate(a,b));
}
public int Multiply(int x, int y)
{
return x * y;
}
public int Multiply2(int x, int y)
{
return x * y + 10;
}
I have a generic Array2D class and want to add an isEmpty getter. However T cannot be compared with default(T) via != in this case. And Equals() cannot be used since the field might be null (but see code below). How would I be able to check whether all fields are empty (i.e. the default value for the reference type or struct/etc.) or not?
So far I came up with the following solution but it already seems rather long-winded to me for a simple isEmpty check and it might not be the optimal way to solve this. Anyone know of a better solution?
public sealed class Array2D<T>
{
private T[,] _fields;
private int _width;
private int _height;
public bool isEmpty
{
get
{
for (int x = 0; x < _width; x++)
{
for (int y = 0; y < _height; y++)
{
if (_fields[x, y] != null && !_fields[x, y].Equals(default(T))) return false;
}
}
return true;
}
}
public Array2D(int width, int height)
{
_width = width < 0 ? 0 : width;
_height = height < 0 ? 0 : height;
_fields = new T[width, height];
}
}
Instead of looping through all of the elements in IsEmpty, simply update the value of IsEmpty when setting a value (requires an indexer but you'll probably need one anyway) :
public class Array2<T>
{
private readonly T[,] _array;
private bool _isEmpty;
public Array2(int width, int height)
{
_array = new T[width, height];
_isEmpty = true;
}
public T this[int x, int y]
{
get { return _array[x, y]; }
set
{
_array[x, y] = value;
_isEmpty = _isEmpty && value.Equals(default(T));
}
}
public bool IsEmpty
{
get { return _isEmpty; }
}
}
Example:
Array2<int> array2 = new Array2<int>(10, 10);
array2[0, 0] = 0;
Console.WriteLine(array2.IsEmpty);
array2[0, 0] = 1;
Console.WriteLine(array2.IsEmpty);
array2[0, 0] = 0;
Console.WriteLine(array2.IsEmpty);
Output:
True
False
False
Obviously this is a trade-off, but imagine that you have 1 million elements in the array, your loop runs 1 million times. With this approach there's no loop, only checking for 2 conditions at any time.
class experiment
{
int xCoord = 0;
int yCoord = 0;
public experiment(int x, int y) {
this.xCoord = x;
this.yCoord = y;
}
}
class result :experiment{
int zCoord = 0;
public result(int z) : base(x,y)
{
this.zCoord = z;
}
}
Can anyone help me solve this simple problem. I'm having an error base(x,y) it says the name 'x' does not exists in the current context and also goes for the y.
x and y are local fields to class experiment they are not visible in inherited class, you may call the base constructor with default values like:
public result(int z) : base(0,0)
Also please follow General Naming Conventions from Microsoft, so the class names begins with upper case character.
EDIT:
It would be better if your child class has a constructor to receive parameter x and y, and the it calls the base class constructor with those values like:
public result(int x, int y, int z) : base(x,y)
{
this.zCoord = z;
}
There is no x,y in constructor of result class.
You pass to your constructor z but tell your base constructor to recieve x and y. Though there are no x and y at that time.
Try this:
public result(int z, int x, int y) : base(x,y)
{
this.zCoord = z;
}
Or set fix values (no variables):
public result(int z) : base(0, 0)
{
this.zCoord = z;
}
I am trying to modify value in dictionary, but the compiler throws KeyNotFoundException. I'm sure, I declared that key in dictionary, because I am calling GenerateEmptyChunks() method, which fills dictionary with chunks with key of their position and values are empty for level generator. I've checked debugger and Chunks dictionary object is correctly filled with keys and values. Is it caused by my unworking CompareTo method? If yes, how I have modify CompareTo method to return right values?
public Dictionary<WPoint, WChunk> Chunks = new Dictionary<WPoint, WChunk>();
GenerateEmptyChunks() method:
public void GenerateEmptyChunks(int Xcount, int Ycount)
{
for(int x = 0; x <= Xcount; x++)
{
for (int y = 0; y <= Ycount; y++)
{
this.Chunks.Add(new WPoint(x, y), new WChunk(x, y));
}
}
}
AddBlock() method which is called by level generator for each tile:
public void AddBlock(WPoint location, int data)
{
this.Chunks[location.GetChunk()].AddTile(new WTile(location, data));
}
WChunk object:
public class WChunk
{
public int ChunkX;
public int ChunkY;
public SortedDictionary<WPoint, WTile> Tiles = new SortedDictionary<WPoint, WTile>();
public WChunk(int posX, int posY)
{
ChunkX = posX;
ChunkY = posY;
}
public void AddTile(WTile tile)
{
Tiles.Add(tile.GetLocation(), tile);
}
}
WPoint object:
public class WPoint : IComparable
{
public float X;
public float Y;
public WPoint(float x, float y)
{
X = x;
Y = y;
}
public WPoint GetChunk()
{
//Oprava pre bloky mensie ako (1,1)
if (X <= 16 && Y <= 16)
{
return new WPoint(0, 0);
}
else
{
double pX = (double)(X / 16);
double pY = (double)(Y / 16);
return new WPoint((int)Math.Floor(pX), (int)Math.Floor(pY));
}
}
public int CompareTo(object obj)
{
WPoint point2 = (WPoint)obj;
if (point2.X == this.X && point2.Y == this.Y)
{
return 0;
}
else if (point2.X >= this.X && point2.Y >= this.Y)
{
return -1;
}
else
{
return 1;
}
}
}
Any ideas why is compiler rejecting keys, when they are in dictionary?
Yes. You have not overridden GetHashCode.
Dictionary is using the GetHashCode and Equals for key comparisons, so implementing the IComparable interface is not enough. Have a look at this answer, that's exactly what you need.