Use a struct as a multidimensional array index - c#

I have a 3D array that I'm accessing this way Array(int x, int y, int z). What I would like to know, if it is possible to have a struct, that has xyz in it, so that I can use it this way: Array(struct xyz). If it is, then how?
The reason for why I would want this, is that it would be easier for me to read and write, and that it would be alot simpler and less error prone to write. Makes it easier to maintain the bigger picture.
I do know that I could make a class that has its own method, but since I have many classes and applying it to each one would make me quickly loose the readability, using the struct directly would be a better option if available.
Example:
public struct xyz
{
public int x, y, z;
public xyz(int X, int Y, int Z)
{
x = X;
y = Y;
z = Z;
}
}
private void Test()
{
int(,,) Array = new int()
{
{
{0,0},
{0,0},
},
{
{0,0},
{0,0},
}
};
xyz XYZ = new xyz(0,0,0);
Array[XYZ] = 1; // this instead of
Array[XYZ.x, XYZ.y, XYZ.z] = 1 // this
}

You could create your own array class that wraps a real array, and provides an indexer to do what you want:
class MyArray<T>
{
private T[,,] array;
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
}

You can easily achieve that by creating your own collection that can be accessed either by specifying all thee coordinates separately:
public T this[int x, int y, int z] { get { … } set { … } }
Or by your XYZ struct:
public T this[XYZ xyz] { get { … } set { … } }
You can't add that indexer to array, extension indexers are not possible. What you could do is to create two extension methods. Something like:
public static T Get<T>(this T[,,] array, XYZ xyz)
{
return array[xyz.X, xyz.Y, xyz.Z];
}
public static void Set<T>(this T[,,] array, XYZ xyz, T value)
{
array[xyz.X, xyz.Y, xyz.Z] = value;
}
And then use it like this:
int i = array.Get(xyz);
array.Set(xyz, 25);
Also, creating mutable structs, like you did, is considered worst practice in C#. They can be very confusing.

Completing the solution of #Andrew Cooper, if you also want to access that matrix normally you must add this methods (Look at the end of Andrew's code)
class MyArray<T>
{
private T[,,] array;
// Constructor
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
// Index with your own struct XYZ
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
// Normal index
public T this[int x, int y , int z]
{
get { return array[x, y, z]; }
set { array[x, y, z] = value; }
}
// Get dimensions
public int GetLength(int dim)
{
return array.GetLength(dim);
}
}

Related

Make struct pointing to different struct in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
class IntComponent
{
public int size;
}
class IntReferenceComponent : IntComponent
{
public IntComponent target; // keep my size same as target size
private void OnValidate()
{
//triggered on target assignment
}
}
Is it possible in C# make struct variable pointing to different struct variable like with objects ? Even with unsafe pointers ?
Edit
The final solution according to Charlieface solution:
public abstract class StructComponent<T> where T : struct
{
public T size;
}
public class IntComponent : StructComponent<int>{ }
public class IntReferenceComponent : IntComponent
{
public IntComponent target;
public new int size
{
get => target.size;
set => target.size = value;
}
}
In Unity I had to create custom editor:
public abstract class StructComponentEditor<T, D> : Editor where T : struct where D : StructComponent<T>
{
public static object StructField(string label, T value, params GUILayoutOption[] options)
{
switch (value)
{
case Vector3 v:
return EditorGUILayout.Vector3Field(label, v, options);
case Vector2 v:
return EditorGUILayout.Vector2Field(label, v, options);
case float f:
return EditorGUILayout.FloatField(label, f, options);
case int i:
return EditorGUILayout.IntField(label, i, options);
case double d:
return EditorGUILayout.DoubleField(label, d, options);
case Color c:
return EditorGUILayout.ColorField(label, c, options);
}
return null;
}
public void DrawDefaultStructComponent()
{
D target = serializedObject.targetObject as D;
PropertyInfo sizeProp = target.GetType().GetProperty("size");
object value;
try
{
value = sizeProp.GetValue(target);
}
catch
{
value = new T();
}
if(sizeProp.SetMethod != null)
{
sizeProp.SetValue(target, StructField("Size", (T)value));
return;
}
StructField("Size", (T)value);
}
public override void OnInspectorGUI()
{
DrawDefaultStructComponent();
DrawDefaultInspector();
}
}
[CustomEditor(typeof(StructComponent<int>), true)]
[CanEditMultipleObjects]
public class IntComponentEditor : StructComponentEditor<int, StructComponent<int>> { }
I need to write something because most of it is just code :)))))) So thanks to everyone who helped :) I love you <3
You don't need to do this in your case, and generally it would be ill-advised to try and mess around with pointers in normal Object Oriented cases, as you don't normally expose the internals of a class.
Instead, just use composition, with an outer property exposing the value of the inner object
class IntReferenceComponent : IntComponent
{
public IntComponent target; // keep my size same as target size
public int Size
{
get => target.size;
set => target.size = value;
}
}
You Can not do this with struct since its value type means you only can take a copy from it and you can't use it as a pointer as you do with classes
Below Code shows that even with pointers unsafe code will not work because you, in the end, will copy the values to a struct to use them,
since you can't access the object attribute with the pointer that
just `point to the object itself (this is what I know )
namespace Feto
{
internal struct Complex
{
public float real;
public float imag;
public Complex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
class FixingComplex
{
public float real;
public float imag;
public FixingComplex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
unsafe class program
{
public static void Main()
{
Complex x = new Complex(10, 20);
Console.WriteLine(x);
Complex* y = &x;
//address of stuct
Console.WriteLine((int)&x);
//the y point to it
Console.WriteLine((int)y);
//what z point to
Console.WriteLine(*y);
//send the addresss of the stuct
addNumbers(y);
Console.WriteLine(x);
Console.ReadKey();
void addNumbers(Complex* result)
{
//make sure it is the same address of stuct
Console.WriteLine((int)result);
//now here we got the address of struct we need to modify it
Console.WriteLine(*result);
//Here is the problem it will take copy
var value = *result;
value.real = 8888;
value.imag = 8888;
//you can use fixedcomplex to go on with pointers and workaround
.....
}
}
}
}
But there is a Solution
with small modifications like passing the address as a reference, not a copy of the address this will workaround and change the values and
The Changes addNumbers(ref y); void addNumbers(ref Complex* result) *result = new Complex(8888,8888);
namespace Feto
{
internal struct Complex
{
public float real;
public float imag;
public Complex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
class FixingComplex
{
public float real;
public float imag;
public FixingComplex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
unsafe class program
{
public static void Main()
{
Complex x = new Complex(10, 20);
Console.WriteLine(x);
Complex* y = &x;
//address of stuct
Console.WriteLine((int)&x);
//the y point to it
Console.WriteLine((int)y);
//what z point to
Console.WriteLine(*y);
//send the addresss of the stuct
addNumbers(ref y);
Console.WriteLine(x);
Console.ReadKey();
void addNumbers(ref Complex* result)
{
//make sure it is the same address of stuct
Console.WriteLine((int)result);
//now here we got the address of struct we need to modify it
Console.WriteLine(*result);
//Here is the problem it will take copy
//var value = *result;
*result = new Complex(8888,8888);
//you can use fixedcomplex to go on with pointers and workaround
}
}
}
}

Extension method on ObservableCollection<MyType>, MyType : IEnumerable<MyType>

I'm having trouble creating an extension method on an ObservableCollection for a custom type. The extension method I need to create is the "ToAnotherType" kind (as in, ToList, ToArray). The MyPoint example implements the IEnumerable interface, but I think I am not exposing the yield correctly?
The real thing obviously has more stuff going on, this is just a stripped down sample in a console app to identify the issue. I've tried changing the OC to a regular List to see if something was going on there, but it's not.
I see many of the "How to make your class Enumerable" examples create a second class derived from List (IE, public class MyPointList : List) but that seems wasteful when the original type can handle it itself, or have it pushed off in a partial class file.
It all looks like it's working until the foreach in the extension method itself- Where I get an error saying 'MyPoint' does not contain a definition for 'X' and 'Y'.
I could obviously handle the conversion with a method that takes in a List and returns a List, but it would be really nice to have the extension.
references as to how I ended up with code I did:
https://www.codeproject.com/Articles/474678/A-Beginners-Tutorial-on-Implementing-IEnumerable-I
https://dotnetcodr.com/2015/07/24/implementing-an-enumerator-for-a-custom-object-in-net-c/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Collections;
namespace EnumerableDemo
{
class Program
{
static void Main(string[] args)
{
var myPoints = new ObservableCollection<MyPoint>
{
new MyPoint(10, 10),
new MyPoint(20, 20),
new MyPoint(30, 30),
new MyPoint(40, 40),
new MyPoint(50, 50)
};
Console.WriteLine("Print a single point via extension method:");
PrintSinglePointToConsole(myPoints[0].ToPoint());
Console.WriteLine("");
Console.WriteLine("Print the whole OC of points:");
PrintPointsToConsole(myPoints.ToPoints());
Console.ReadLine();
}
public static void PrintSinglePointToConsole(Point point)
{
Console.WriteLine("Point {0},{1}", point.X, point.Y);
}
public static void PrintPointsToConsole(List<Point> points)
{
foreach (var item in points)
{
Console.WriteLine("Point: {0},{1}", item.X, item.Y);
}
}
}
public class MyPoint : IEnumerable<MyPoint>
{
private List<MyPoint> _myPoints = new List<MyPoint>();
private int _x { get; set; } = 0;
public int X { get { return _x; } set { _x = value; } }
private int _y { get; set; } = 0;
public int Y { get { return _y; } set { _y = value; } }
public MyPoint()
{
}
public MyPoint(int x, int y)
{
_x = x;
_y = y;
}
public IEnumerator<MyPoint> GetEnumerator()
{
foreach (var item in _myPoints)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class MyPointExtension
{
public static Point ToPoint(this MyPoint point)
{
return new Point(point.X, point.Y);
}
public static List<Point> ToPoints<MyPoint>(this ObservableCollection<MyPoint> list)
{
var result = new List<Point>();
foreach (var item in list)
{
//Line with error:
//'MyPoint' Does not contain a definition for 'X' and no extension method for
//'X' accepting a first argument type of 'MyPoint' could be found.
result.Add(new Point(item.X, item.Y));
}
return result;
}
}
}
You don't need a MyPoint generic parameter in ToPoints.
Just use
public static List<Point> ToPoints(this ObservableCollection<MyPoint> list)
And the result is:
Print a single point via extension method:
Point 10,10
Print the whole OC of points:
Point: 10,10
Point: 20,20
Point: 30,30
Point: 40,40
Point: 50,50
BTW, you can also make a code a bit cleaner and shorter if you discard the _x and _y fields, like this:
public int X { get; set; } = 0;
public int Y { get; set; } = 0;
public MyPoint(int x, int y)
{
X = x;
Y = y;
}
Final code block, which makes use of the other extension method ToPoint
public static List<Point> ToPoints(this ObservableCollection<MyPoint> list)
{
var result = new List<Point>();
foreach (var item in list)
{
result.Add(item.ToPoint());
}
return result;
}

How a function can be automatically called upon a variable change?

I have a class consisting of variable members and a function member. The variable member occasionally changes. I want the function to be called automatically upon the variable changes. In other words, how can I tie the variables inside a class?
class line
{
double x, y; // The poition of the lind end. The line starts at the origin (0,0)
double l; // The length of the line
void length()
{
l = Math.sqrt(x*x+y*y);
}
}
In example above, I need the length to be updated when x and y change.
Make your variables into properties, then put your functions in the set accesors.
class line
{
double _x, _y;
double x
{
get { return _x; }
set
{
_x = value;
length();
}
}
double y
{
get { return _y; }
set
{
_y = value;
length();
}
}
double l; // The length of the line
void length()
{
l = Math.Sqrt(_x * _x + _y * _y);
}
}
If you define properties, on your class, you can make X and Y autoprops, then make a read-only property L that is calculated from these values:
public class Line //class names should be Capitalized
{
public double X{ get; set; } //prop names should be Capitalized
public double Y{ get; set; }
public double L{
get{
return Math.Sqrt(X * X + Y * Y);
}
}
}
you can you properties
int x
int X {
get { return x; }
set { x = value; YouMethod();}
}
You can achieve pretty similar behavior using calculated property like
double Length
{
get { return Math.sqrt(x*x+y*y); }
}
The only caveat is that calculation is performed upon each call to Length even if x and y haven't changed.
You can encapsulate you x and y fields into properties and call length function from setter like
double X
{
get { return x; }
set
{
x = value;
length();
}
}
double Y
{
get { return y; }
set
{
y = value;
length();
}
}
and then change x and y ONLY via X and Y properties.
As BenJ noted, you can use properties.
Instead of declaring x and y as simple fields inside the class. You can declare them as properties the following way :
private double x;
public double X
get
{
return this.x;
}
set
{
this.x = value;
this.length()
//Above line will call your desired method
}

C# Adding classes with one another

So I was playing around with "Vectors" in C# I created my own Vector class.
What I tried to do was to add two vectors with each other by a simple "+".
This is my vector class:
class createVector
{
//My x,y,z coordinates
public int x { get; set; }
public int y { get; set; }
public int z { get; set; }
//constructor
public createVector(int X, int Y, int Z=0)
{
x = X;
y = Y;
z = Z;
}
// Convert to String
public override string ToString()
{
return string.Format("X:{0,-5}\nY:{1,-5}\nZ:{2,-5}", x, y, z);
}
}
And what I attempted to do was this:
createVector Vector1 = new createVector(1, 2);
createVector Vector2 = new createVector(3, 4, 5);
createVector Vector 3 = Vector1 + Vector2;
I don't want to use a function to add the Vectors together.
Is it possible for me to do something like this?
You need to overload the + operator inside the class:
public static Vector operator +(Vector v1, Vector v2)
{
// do logic here then return a vector
return new Vector ();
}
It is better to follow .NET naming conventions and have your class named Vector and not createVector. It should be a noun and using PascalCase .

Vector math dimension consistency check at compile-time

I am creating a linear algebra library in C#, and I would like to force dimension inconsistency errors up to compile-time. I've implemented a similar solution to this, where the trait I use is a class that uniquely maps to an integer. The problem is for every possible size I would like my Vectors to have, I would need to create a class with a unique name to represent it.
Here is an example of that implementation:
public class Vector<T> where T: ISize, new()
{
static readonly T size = new T();
List<double> values;
public Vector(List<double> values)
{
if (values.Count != size.Size)
throw new IndexOutOfRangeException();
this.values = new List<double>(values);
}
public double Get(int index)
{
return values[index];
}
public Vector<T> Add(Vector<T> other)
{
var vv = new List<double>();
for (int ii = 0; ii < size.Size; ++ii)
vv.Add(other.Get(ii) + this.values[ii]);
return new Vector<T>(vv);
}
}
public interface ISize
{
int Size { get; }
}
public class S1 : ISize
{
public int Size
{
get { return 1; }
}
}
public class S2 : ISize
{
public int Size
{
get { return 2; }
}
}
And here's an example of its usage:
class Program
{
static void Main(string[] args)
{
var v1 = new Vector<S2>(new List<double>() { 1, 2 });
var v2 = new Vector<S2>(new List<double>() { 10, -4 });
var z1 = new Vector<S1>(new List<double>() { 10 });
// works
var v3 = v1.Add(v2);
// complie-time error
var z2 = z1.Add(v1);
}
}
This works quite well for my purposes, except for the fact that I would need to create a different implementation of ISize for every possible Vector size. Is there any way for me to implement the Vector class that would allow me to get around this problem?
In order to get a compile-time error, you need to have different types. C# does not have a concept that let's you define a type parameter that itself takes a kind of value parameters - which is what you would need to do this.
Therefore, I don't think what you are asking is possible.
I think there might be a way to make unique types for family of vector instances using anonymous types, but that's going to be quirky and I don't think it would provide the type safety that you want.
C++ has such a concept in templates (so it's not unreasonable), just not possible in C#.
You can create a single N-dimentional Vector class with compile time type checking, but it's pretty messy. What we're creating here is LISP style linked-lists, but through generic type arguments rather than purely out of object references via fields.
public interface IVector
{
double Value { get; }
IVector Tail { get; }
}
public class Vector<T> : IVector
where T : IVector
{
internal Vector(double value, T tail)
{
Value = value;
Tail = tail;
}
public double Value { get; private set; }
public T Tail { get; private set; }
public Vector<Vector<T>> Add(double value)
{
return new Vector<Vector<T>>(value, this);
}
}
internal class EmptyVector : IVector
{
public double Value
{
get { throw new NotImplementedException(); }
}
public IVector Tail
{
get { return null; }
}
}
public static class Vector
{
public static readonly Vector<IVector> Empty = new Vector<IVector>(
0, new EmptyVector());
public static IEnumerable<double> AllValues(this IVector vector)
{
IVector current = vector;
while (current != Vector.Empty && current != null)
{
yield return current.Value;
current = current.Tail;
};
}
}
This allows us to write:
var v1 = Vector.Empty.Add(1).Add(2);
var v2 = Vector.Empty.Add(10).Add(-4);
var z1 = Vector.Empty.Add(10);
v1 = v2;//works, as they are the same type
z1 = v2;//fails, as they aren't the same type, since they're a different size
This allows allows you to write a method that accepts a vector of a particular size. It's not convenient, and it doesn't scale, but it works. If you want, say, a 3D vector as a parameter, you can write:
public static void Foo(Vector<Vector<Vector<IVector>>> vector)
{
var first = vector.Value;
var second = vector.Tail.Value;
var third = vector.Tail.Tail.Value;
}

Categories