overloading operator c# Vector - c#

So, I am trying to override the "-" operator in c# to be able to subtract 2 vectors, but my class cannot implement Vector.
namespace Vectors
{
class VectorUtilv
{
private Point _p;
private Point _p2;
private Vector _v;
public Vector V
{
get { return _v; }
set { _v = value; }
}
public Point AddVector(Vector v)
{
_p.X = (_p.X + v.X);
_p2.Y = (_p.Y + v.Y);
return _p2;
}
// This is where I am trying to override but I cant add the v.X or
// the v.Y because it is not a vector. If i cast it as a vector the
// override doesn't work.
//////////////////////////////////////////////////////////////////
public static VectorUtilv operator -(Vector a, Vector b)
{
Vector v = new Vector();
v.X = a.X - b.X;
v.Y = a.Y - b.Y;
return v;
}
}
}
Any idea how I can remedy this issue?

Because you are Trying to define Operator for Class. At least one of its Parameters should be used in Operator with Type of your Class. for example you cant have class Car and define Operator witch only Gets int.
You can't override the operator for existing classes.only your own classes.
If you cant Modify Vector Class then you should declare your own class named Vector. or use the Type of your class for operator.
so you can have
class VectorUtilv
{
private Point _p;
private Point _p2;
private Vector _v;
public static VectorUtilv operator -(VectorUtilv a, VectorUtilv b)
{
//...
}
}
or
class Vecotr
{
private Point _p;
private Point _p2;
private Vector _v;
public static Vecotr operator -(Vecotr a, Vecotr b)
{
//...
}
}
But if you use solution 2. then you need to use qualifiers when using Vector.
System.Windows.Vector // is in Windows assembly
Vector // is your class

You can only override an operator in its own class.
Move all of that code to the Vector class.

In your vector class, override the '-' operator in it
public class Vector
{
public int X { get; set; }
public int Y { get; set; }
public static Vector operator -(Vector a, Vector b)
{
Vector v = new Vector();
v.X = a.X - b.X;
v.Y = a.Y - b.Y;
return v;
}
}
Then, you can uses it like that
Vector v1 = new Vector { X = 5, Y = 9};
Vector v2 = new Vector { X = 3, Y = 4 };
Vector vr = v1 - v2;
Console.WriteLine("Resultant Vector X: {0} & Y:{1}", vr.X, vr.Y);
I hope it will help you.

Thanks for the great responses. I wish I would I have checked before I figured it out. Would have saved me lots of time. I ended up doing pretty much exactly as you all said. Here is what I have.
public static VectorUtil operator -(VectorUtil aHeroPoint, VectorUtil bEnemyPoint) {
VectorUtil v = new VectorUtil();
v.Vec = new Vector(( aHeroPoint._p.X - bEnemyPoint._p.X),( aHeroPoint._p.Y - bEnemyPoint._p.Y));
return v;
}

Related

How can i convert the date type of the object to another?

This is my code I wrote a comment under the mistake. I am not allowed to do it in another way it should be two classes and it should be done in this way. If someone can help me i would appreciate this
Thank u
using System;
using MathLibrary;
namespace MathLibraryApp
{
class Program
{
static void Main(string[] args)
{
Vector v = new Vector();
Vector v1 = new Vector(4, 8, 12);
Vector v2 = new Vector(8,16,24);
Vector[] vectors = { v1, v2 };
Console.WriteLine(v.Add(vectors));
}
}
}
using System;
namespace MathLibrary
{
public class PointVectorBase
{
public PointVectorBase(double x=0 , double y=0 , double z=0 )
{
this.X = x;this.Y = y;this.Z = z;
}
protected virtual PointVectorBase CalculateSum(params Vector[] addends)
{
for (int i = 0; i < addends.Length; i++)
{
this.X = this.X + addends[i].X;
this.Y = this.Y + addends[i].Y;
this.Z = this.Z + addends[i].Z;
}
return this;
}
}
public class Vector : PointVectorBase
{
public Vector(double x = 0, double y = 0, double z = 0) : base(x, y, z){ }
public Vector Add(params Vector[] addends)
{
return this.CalculateSum(addends) ;
//Cannot implicitly convert type MathLibrary.PointVectorBase to MathLibrary.Vector. An explicit conversion exists (are you missing a cast?)
}
}
}
You can either cast the result like this:
public Vector Add(params Vector[] addends)
{
return this.CalculateSum(addends) As Vector;
}
This is dangerous though. Not all base vectors are vectors so you could have a null return. Same way as an animal is not always a cat in the public class cat: animal example.
Creating the implicit conversion is safer, though not always possible: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators
Your method CalculateSum returns value type PointVectorBase. Method Add in Vector class should return Vector.
Due to inheritance you can cast result of a CalculateSum to a Vector so it would be return this.CalculateSum(addends) as Vector;
In this case I wouldn't go for inheritance. You are only extending the base class with methods.
The problem on your CalculateSum is that you're returning this as a result. Which is a strange pattern. Either go for a void method which alters the current instance or return a new instance (so leave the current instance unmodified). I would go for the latter.
If your question is about inheritance, this is not a good example you gave.
But if you want an other way:
In your example I would go for extension methods. Also this is a nice case to use structs. By writing extension methods, you can extend the Vector3 with extra methods..
using System;
namespace MathLibrary
{
public struct Vector3
{
public double X;
public double Y;
public double Z;
public Vector3(double x=0 , double y=0 , double z=0 )
{
this.X = x;
this.Y = y;
this.Z = z;
}
public Vector3 CalculateSum(params Vector3[] addends)
{
var result = new Vector3();
for (int i = 0; i < addends.Length; i++)
{
result.X = result.X + addends[i].X;
result.Y = result.Y + addends[i].Y;
result.Z = result.Z + addends[i].Z;
}
return result;
}
}
public static class VectorExtensions
{
public static Vector3 Add(this Vector3 vector, params Vector3[] addends)
{
return vector.CalculateSum(addends);
// the add should actually add to the current vector,
// which makes it less readable.. calculate sum and add is almost the same.
return vector.CalculateSum(
new Vector3 [] { vector }
.Concat(addends)
.ToArray() );
}
}
}
The more your code has a functional approach the less strange things will happen.

double[]=operator/(double[] a,double[] b) or Vector[]=operator/(Vector[] a, Vector[] b); Why can I not do this? Even just for myself? [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 years ago.
Improve this question
I want to overload math and the array and [] to do mathematical operation
After a lot of up and back, the answer is the design of c# won't let you overload even for yourself 'build-in' types like you can in c++.
This is subject to a lot of debate and may emerge in the future as a feature.
Old c programmers moving (grudgingly to c#) will demand this. I demand this.
For example, I have lots of derived types for openGL such as Vertex x. I want to add them, make arrays of them, find them. Inherit them into bigger objects such as triangle or quad strips.
Specifically, I want to overload binary operators for =/ accumulator operators.
Below, I answer my question.
The secret is in C++ you can overload =/ TOKEN.
=/ is short for a=a/b. the operator =/ is ONE token.
In c# it is TWO tokens, and you can't overload the assignment(=) (use an implicit conversion or an explicit cast), you overload the
operator as a binary second token.
For example:
class Vertex{
public float x,y,z;
public Vertex(){get;set}
int some_small_int=2;
Vertex[] A=new Vertex[some_small_int];
Vertex[] B=new Vertex[some_small_int];
Vertex[] C=new Vertex[some_small_int];
public static Vertex[] operator+(Vertex[] A, Vertex[] B)
{
Vertex[] C=new Vertex[A.Count()];
for( int i=0;i< A.Count();i++)
{
C[i]=A[i]+B[i];
}
return C;
}
}
}
... insert into Vertex class...
array Vertex plus(array Vertex A, array Vertex B){
array Vertex C=new array<vertex>[A.Count()]; // B.Count() better be the same.
for(int i=0;i<A.Count();i++)
{
C[i].x=A[i].x+B[i].x;
C[i].y=A[i].y+B[i].y;
C[i].z=A[i].z+B[i].z;
}
}
Why can't do this in c#?
Because it is designed that way. I would have to write a class Float (as a wrapper for float).
Here is a whole listing for a Vector3 class in order to get ideas on how to implement operators and indexers.
[ImmutableObject(true)]
public struct Vector3 : IEnumerable<float>, ICloneable
{
readonly float x, y, z;
#region Definition
public Vector3(float x, float y, float z)
{
this.x=x;
this.y=y;
this.z=z;
}
public Vector3(double x, double y, double z)
: this((float)x, (float)y, (float)z) { }
public Vector3(Vector3 other)
{
this.x=other.x;
this.y=other.y;
this.z=other.z;
}
public Vector3(string description)
: this()
{
FromString(description);
}
/// <summary>
/// Indexer allows the use of the '[]' operator in Vector3
/// </summary>
/// <param name="index">The integer index 0-2</param>
/// <returns>A scalar value</returns>
public float this[int index]
{
get
{
switch (index)
{
case 0: return this.x;
case 1: return this.y;
case 2: return this.z;
}
throw new IndexOutOfRangeException();
}
}
public float X { get { return x; } }
public float Y { get { return y; } }
public float Z { get { return z; } }
public float Magnitude { get { return Norm(); } }
public float Norm() { return (float)Math.Sqrt(x*x+y*y+z*z); }
public Vector3 Normalized() { var m=Norm(); if (m>0) return this/m; return this; }
public static readonly Vector3 O=new Vector3(0, 0, 0);
public static readonly Vector3 I=new Vector3(1, 0, 0);
public static readonly Vector3 J=new Vector3(0, 1, 0);
public static readonly Vector3 K=new Vector3(0, 0, 1);
public static explicit operator float[](Vector3 vector)
{
return vector.ToArray();
}
#endregion
#region Math
public Vector3 Add(Vector3 other, float scale=1)
{
return new Vector3(
x+scale*other.x,
y+scale*other.y,
z+scale*other.z);
}
public Vector3 Scale(float scale)
{
return new Vector3(
scale*x,
scale*y,
scale*z);
}
public Vector3 Multiply(Matrix3 rhs)
{
return new Vector3(
X*rhs.A11+Y*rhs.A12+Z*rhs.A13,
X*rhs.A21+Y*rhs.A22+Z*rhs.A23,
X*rhs.A31+Y*rhs.A32+Z*rhs.A33);
}
public Vector3 Reciprocal(float numerator)
{
return new Vector3(numerator/x, numerator/y, numerator/z);
}
public static float Dot(Vector3 v1, Vector3 v2)
{
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
}
public static Vector3 Cross(Vector3 v1, Vector3 v2)
{
return new Vector3(
v1.y*v2.z-v1.z*v2.y,
v1.z*v2.x-v1.x*v2.z,
v1.x*v2.y-v1.y*v2.x);
}
public static float AngleBetween(Vector3 v1, Vector3 v2)
{
var cos=Dot(v1, v2);
var sin=Cross(v1, v2).Norm();
return (float)Math.Atan2(sin, cos);
}
public Vector3 AlongX() { return new Vector3(x, 0, 0); }
public Vector3 AlongY() { return new Vector3(0, y, 0); }
public Vector3 AlongZ() { return new Vector3(0, 0, z); }
public Vector3 AlongXY() { return new Vector3(x, y, 0); }
public Vector3 AlongYZ() { return new Vector3(0, y, z); }
public Vector3 AlongZX() { return new Vector3(x, 0, z); }
public Vector3 RotateAbout(Vector3 axis, float angle)
{
return Matrix3.RotateAbout(axis, angle)*this;
}
public Vector3 RotateAboutX(float angle)
{
float cos=(float)Math.Cos(angle), sin=(float)Math.Sin(angle);
return new Vector3(
x,
y*cos-z*sin,
y*sin+z*cos);
}
public Vector3 RotateAboutY(float angle)
{
float cos=(float)Math.Cos(angle), sin=(float)Math.Sin(angle);
return new Vector3(
x*cos+z*sin,
y,
-x*sin+z*cos);
}
public Vector3 RotateAboutZ(float angle)
{
float cos=(float)Math.Cos(angle), sin=(float)Math.Sin(angle);
return new Vector3(
x*cos-y*sin,
x*sin+y*cos,
z);
}
public Vector3 MirrorAboutXY() { return new Vector3(x, y, -z); }
public Vector3 MirrorAboutXZ() { return new Vector3(x, -y, z); }
public Vector3 MirrorAboutYZ() { return new Vector3(-x, y, z); }
#endregion
#region Operators
public static Vector3 operator+(Vector3 lhs, Vector3 rhs) { return lhs.Add(rhs); }
public static Vector3 operator-(Vector3 rhs) { return rhs.Scale(-1); }
public static Vector3 operator-(Vector3 lhs, Vector3 rhs) { return lhs.Add(rhs, -1); }
public static Vector3 operator*(float lhs, Vector3 rhs) { return rhs.Scale(lhs); }
public static Vector3 operator*(Vector3 lhs, float rhs) { return lhs.Scale(rhs); }
public static Vector3 operator/(Vector3 lhs, float rhs) { return lhs.Scale(1/rhs); }
public static Vector3 operator/(float lhs, Vector3 rhs) { return rhs.Reciprocal(lhs); }
public static float operator*(Vector3 lhs, Vector3 rhs) { return Dot(lhs, rhs); }
public static Vector3 operator^(Vector3 lhs, Vector3 rhs) { return Cross(lhs, rhs); }
public static Vector3 operator*(Vector3 lhs, Matrix3 rhs)
{
return lhs.Multiply(rhs);
}
#endregion
#region ICloneable Members
public Vector3 Clone() { return new Vector3(this); }
object ICloneable.Clone()
{
return Clone();
}
#endregion
#region IEnumerable<float> Members
public IEnumerator<float> GetEnumerator()
{
yield return x;
yield return y;
yield return z;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(Vector3)</code></returns>
public override bool Equals(object obj)
{
if (obj is Vector3)
{
return Equals((Vector3)obj);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="Vector3"/> classes
/// </summary>
/// <param name="other">The other <see cref="Vector3"/> to compare it to</param>
/// <returns>True if equal</returns>
public bool Equals(Vector3 other)
{
return x.Equals(other.x)
&&y.Equals(other.y)
&&z.Equals(other.z);
}
/// <summary>
/// Calculates the hash code for the <see cref="Vector3"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
return ((17*23+x.GetHashCode())*23+y.GetHashCode())*23+z.GetHashCode();
}
}
#endregion
#region IFormattable Members
public override string ToString()
{
return ToString("G");
}
public string ToString(string format)
{
return ToString(format, CultureInfo.CurrentCulture.NumberFormat);
}
public string ToString(string format, IFormatProvider formatProvider)
{
return string.Format("({0},{1},{2})",
x.ToString(format, formatProvider),
y.ToString(format, formatProvider),
z.ToString(format, formatProvider));
}
#endregion
#region Triangles
public static float TriangleArea(Vector3 a, Vector3 b, Vector3 c)
{
Vector3 u=b-a, v=c-a;
Vector3 k=Vector3.Cross(u, v);
return k.Magnitude/2;
}
public static Vector3 TriangleNormal(Vector3 a, Vector3 b, Vector3 c)
{
Vector3 u=b-a, v=c-a;
return Vector3.Cross(u, v).Normalized();
}
#endregion
#region IParsable Members
public void FromString(string description)
{
// "(X,Y,Z)" => (X,Y,Z)
description=description.Trim('(', ')');
var parts=description.Split(',');
if (parts.Length==3)
{
float new_x=0, new_y=0, new_z=0;
if (!float.TryParse(parts[0].Trim(), out new_x))
{
new_x=x;
}
if (!float.TryParse(parts[1].Trim(), out new_y))
{
new_y=y;
}
if (!float.TryParse(parts[2].Trim(), out new_z))
{
new_z=z;
}
this=new Vector3(new_x, new_y, new_z);
}
}
public float[] ToArray()
{
return new float[] { x, y, z };
}
#endregion
}
Some example usage here:
public TestVector()
{
Vector3 A=new Vector3(1, 2, 3);
Vector3[] array=new Vector3[100];
array[0]=A;
for (int i=1; i<100; i++)
{
array[i]=2*array[i-1]+Vector3.Cross(array[i], Vector3.I);
// or 2*array[i-1]+(array[i]^Vector3.I);
}
float Ax = A[0];
float max_x=array.Max((v) => v.X);
}
I now understand the issue.
The implementation of c# (=) assignment then (+) addition as two operators, not a single operator (=+) summation.
In c++ (=) is one token that is a unary operator that can be overloaded..
in c++
a=+b is shorthand for a=a+b
in c#
a=+b expands into a=a+b but it is not the equality operator that can be overloaded but the addition operator as a binary operator.
So the solution to overloading is to overload the plus, minus, multiplication, division, etc for the types required as binary operators, not unary operators.
Surprisingly, this seems to compile to compute the centroid of a Boxel Type, that consists of an array of edges, each edge has two vertices. I have yet to test the run time code but think it will work now.
public static Vertex operator / ( Vertex a , int b )
{
Vertex c = new Vertex ( );
c . x = a . x / b;
c . y = a . y / b;
c . z = a . z / b;
return c;
}
public static Vertex operator + ( Vertex a , Vertex b )
{
Vertex c = new Vertex ( );
c . x = a . x + b . x;
c . y = a . y + b . y;
c . z = a . z + b . z;
return c;
}
Vertex NewCentroid ( Boxel B )
{
Vertex C = new Vertex();
C = NewCentroid ( B . E );
return C;
}
Vertex NewCentroid ( Edge [ ] E )
{
Vertex C = new Vertex ( ){0.0,0.0,0.0};
foreach ( Edge e in E )
{
C **+** = NewCentroid ( e );
}
return C;
}
Vertex NewCentroid ( Edge e )
{
Vertex C = new Vertex ( );
C = NewCentroid ( e . V0 , e . V1 );
return C;
}
Vertex NewCentroid ( Vertex v0 , Vertex v1 )
{
Vertex C = new Vertex ( );
C = v0 **+** v1;
C =**/** 2.0;
return C;
}
Correct me if I am wrong. I'm old and decrepit in my programming ways.
Cap Sigma is the big greek letter usually taken as summation from downstairs subscript to upstairs superscript.
Now being symbol minded and old and decrepit I am happier.
I retract my accusation about c# being mathematically innumerate/illiterate.
You have
public static Vertex[] operator+(Vertex[] A, Vertex[] B)
{
return new vertex[] { A.x+B.x, A.y+B.y, A.z+B.z };
}
but
return new vertex[] { A.x+B.x, A.y+B.y, A.z+B.z };
is not a valid expression since for Vertex[] A there is no A.x.
Quick lambda solution:
return A.Zip(B, (v1, v2) => new Vertex(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z)).ToArray();
Whereas the latter new Vertex() expression could also be simplified if you overload the + operator of the Vertex object.
So, in no way is "Is c# mathematically illiterate/innumerate". Just a little bit of System.Linq needed to make it a nice expression.
This is basically component-wise vector addition implemented in C# with operator overloading. Also see http://www.dotnetperls.com/zip.
EDIT: Nope, in fact I was wrong. You can only overload operators from the enclosing class, so no direct overloads for a Vertex[] unless you declar Vertex[] as own wrapper class. But here is a complete, working code with some operator overloading and vector addition.
using System.IO;
using System;
using System.Linq;
class Vertex
{
public float x,y,z;
public Vertex(float _x, float _y,float _z) {
x = _x;
y = _y;
z = _y;
}
public static Vertex operator+(Vertex v1, Vertex v2)
{
return new Vertex(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z);
}
public static Vertex[] AddVertices(Vertex[] A, Vertex[] B)
{
return A.Zip(B, (v1, v2) => v1 + v2).ToArray();
}
public override String ToString() { return string.Format("({0}, {1}, {2})",x,y,z);}
}
class Program
{
const int some_small_int=2;
static Vertex[] A=new Vertex[]{ new Vertex(10.0f, 10.0f, 10.0f),new Vertex(10.0f, 10.0f, 10.0f)};
static Vertex[] B=new Vertex[]{new Vertex(10.0f, 10.0f, 10.0f),new Vertex(10.0f, 10.0f, 10.0f)};
static Vertex[] C= Vertex.AddVertices(A,B);
static void Main()
{
Console.WriteLine("Vertex Array A:");
foreach(var vert in A) Console.WriteLine(vert);
Console.WriteLine("Vertex Array B:");
foreach(var vert in B) Console.WriteLine(vert);
Console.WriteLine("Vertex Array C:");
foreach(var vert in C) Console.WriteLine(vert);
var vert1 = new Vertex(1,2,3);
var vert2 = new Vertex(4,5,6);
var vert3 = vert1 + vert2;
Console.WriteLine("Vertex v1 + v2:" + vert3.ToString());
}
}

Operator overloading placement and redundancy

I have multiple structs as follows: Vector2, Vector3, Vector4. Each struct has operator overloads defined for basic arithmetic operations as well as implicit and explicit casting.
So far, I have added all possible combinations in the Vector4 class:
public static Vector4 operator + (Vector4 v1, Vector4 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector4 v1, Vector3 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector3 v1, Vector4 v2) { return (new Vector4(...)); }
public static implicit operator Vector4 (Vector2 v) { return (new Vector4(v)); }
public static implicit operator Vector4 (Vector3 v) { return (new Vector4(v)); }
public static explicit operator Vector3 (Vector4 v) { return (new Vector3(v)); }
public static explicit operator Vector2 (Vector4 v) { return (new Vector2(v)); }
Is there a guideline as to which operators are a better fit in which struct? I can't imagine hurting performance either way but am interested in knowing what would be more intuitive for other developers if they came across this code. The number of operator combinations quickly goes into the dozens.
By the way, duplicating these operators in other classes is not causing a compile time error. I have not checked which implementation would be called but that's besides the point.
If each class represents two, three and four-dimensional vectors, I think it should be possible for you to reduce your code somewhat. That's because the definitions of vector arithmetic between vectors of differing dimension are redundant as long as you have the necessary implicit up-conversions. Thus operators like the following will not be needed:
public static Vector4 operator + (Vector4 v1, Vector3 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector3 v1, Vector4 v2) { return (new Vector4(...)); }
I'd also suggest making the lower-dimension vectors handle up-conversions to, and down-conversions from, higher dimension vectors. That's because down-conversion strips information, and the choice of how to do it should be in the "more limited" struct.
Thus, VectorI structs would need implicit up-conversions to all VectorI+J and explicit down-conversions to all VectorI-J structs. In addition, the VectorI structs would need to implement their own vector arithmetic. But since 'I' only has values 2, 3 and 4, that means:
Vector2 needs implicit conversions to Vector3 and Vector4, as well as explicit down-conversions from Vector3 and Vector4.
Vector3 needs implicit conversions to Vector4 as well as explicit down-conversions from Vector4.
Vector4 needs no conversions.
All 4 structs implement linear algebra methods for themselves, between vectors of the same dimension only.
I just tested this scheme and adding disparate Vector2, Vector3 and Vector4 structs works as expected with the implicit conversion being done.
Update
Just made a quick prototype implementation for addition, and all the cross-dimension additions work as expected:
public struct Vector2
{
public double x, y;
public Vector2(double x, double y)
{
this.x = x; this.y = y;
}
#region linear algebra
public static Vector2 operator +(Vector2 first, Vector2 second)
{
return new Vector2(first.x + second.x, first.y + second.y);
}
#endregion
#region conversions to/from higher dimensions
public static implicit operator Vector3(Vector2 v2)
{
return new Vector3(v2.x, v2.y, 0);
}
public static implicit operator Vector4(Vector2 v2)
{
return new Vector4(v2.x, v2.y, 0, 0);
}
public static explicit operator Vector2(Vector3 v3)
{
return new Vector2(v3.x, v3.y);
}
public static explicit operator Vector2(Vector4 v4)
{
return new Vector2(v4.x, v4.y);
}
#endregion
}
public struct Vector3
{
public double x, y, z;
public Vector3(double x, double y, double z)
{
this.x = x; this.y = y; this.z = z;
}
#region linear algebra
public static Vector3 operator +(Vector3 first, Vector3 second)
{
return new Vector3(first.x + second.x, first.y + second.y, first.z + second.z);
}
#endregion
#region conversions to/from higher dimensions
public static implicit operator Vector4(Vector3 v3)
{
return new Vector4(v3.x, v3.y, v3.z, 0);
}
public static explicit operator Vector3(Vector4 v4)
{
return new Vector3(v4.x, v4.y, v4.z);
}
#endregion
}
public struct Vector4
{
public double x, y, z, w;
public Vector4(double x, double y, double z, double w)
{
this.x = x; this.y = y; this.z = z; this.w = w;
}
#region linear algebra
public static Vector4 operator +(Vector4 first, Vector4 second)
{
return new Vector4(first.x + second.x, first.y + second.y, first.z + second.z, first.w + second.w);
}
#endregion
}
The following test code then works OK:
public static class VectorHelper
{
public static void Test()
{
var v2 = new Vector2(5, 5);
var v3 = new Vector3(7, 7, 7);
var v4 = new Vector4(3, 3, 3, 3);
var res1 = v2 + v3;
Debug.Assert(res1.GetType().Name == "Vector3"); // No assert
var res2 = v3 + v4;
Debug.Assert(res2.GetType().Name == "Vector4"); // No assert
var res3 = v2 + v4;
Debug.Assert(res3.GetType().Name == "Vector4"); // No assert
Debug.Assert(res3.x == 8 && res3.y == 8 && res3.z == 3 && res3.w == 3); // No assert
}
}

C# Abstract Class Operator Overload

I have an abstract class, Vector, which I would like to overload the operators +,-,*, etc.
I want any derived classes to be able to use these, and get an object back with the same type as the calling object.
I tried with generics, (as follows, in brief), but I couldn't find a legal way to do it:
public static T operator +<T>( T V1, T V2) where T : Vector
{
//some calculation
return new T(args);
}
I then tried to do it just using the base class:
public static Vector operator+(Vector V1, Vector V2)
{
if (V1.Dimension != V2.Dimension)
throw new VectorTypeException("Vector Dimensions Must Be Equal");
double[] ArgList = new double[V1.Dimension];
for (int i = 0; i < V1.Dimension; i++) { ArgList[i] = V1[i] + V2[i]; }
return (Vector)Activator.CreateInstance(V1.GetType(), new object[] { ArgList});
}
If this method is passed in two child objects, it should perform the operation on them, and return a new object of the same heritage.
The problem I ran into with this is that I cannot enforce that all such child classes must have a constructor with the appropriate signature, and I can't call the base constructor to make the object.
What are ways to either (a) Make either of these work, or (b) do this elegantly in another way?
You could declare instance-level abstract methods which your subclass can override:
public abstract class Vector
{
protected abstract Vector Add(Vector otherVector);
public static Vector operator +(Vector v1, Vector v2)
{
return v1.Add(v2);
}
}
public class SubVector : Vector
{
protected override Vector Add(Vector otherVector)
{
//do some SubVector addition
}
}
Might run into some issues especially with multiple subclasses (Will SubVector have to know how to add with SomeOtherSubVectorClass? What if you add ThirdVectorType class?) and perhaps handling null cases. Also, making sure that SubVector.Add behaves the same as SomeOtherSubVectorClass.Add when it comes to commutative operations.
EDIT: based on your other comments, you could so something like:
public class Vector2D : Vector
{
public double X { get; set; }
public double Y { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector2D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = otherVector3D.Z };
//handle other cases
}
}
public class Vector3D : Vector
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector3D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y, Z = this.Z };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = this.Z + otherVector3D.Z };
//handle other cases
}
}
EDITx2:
Given your latest comment, perhaps your should just maintain an internal array/matrix and just do generic matrix math. Your subclasses can expose X/Y/Z property wrappers against the array indicies:
public class Vector
{
protected double[] Values;
public int Length { get { return Values.Length; } }
public static Vector operator +(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
return new Vector() { Values = newValues };
}
}
}
public class Vector2D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
}
public class Vector3D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
public double Z
{
get { return Values[2]; }
set { Values[2] = value; }
}
}
EDITx3: Based on your latest comment, I guess you could implement operator overloads on each subclass, do the shared logic in a static method (say in the base Vector class), and somewhere do a switch/case check to provide a specific subclass:
private static Vector Add(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
switch (newValues.Length)
{
case 1 :
return new Vector1D() { Values = newValues };
case 2 :
return new Vector2D() { Values = newValues };
case 3 :
return new Vector3D() { Values = newValues };
case 4 :
return new Vector4D() { Values = newValues };
//... and so on
default :
throw new DimensionOutOfRangeException("Do not support vectors greater than 10 dimensions");
//or you could just return the generic Vector which doesn't expose X,Y,Z values?
}
}
}
Then your subclasses would have:
public class Vector2D
{
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return (Vector2D)Add(v1, v2);
}
}
public class Vector3D
{
public static Vector3D operator +(Vector3D v1, Vector3D v2)
{
return (Vector3D)Add(v1, v2);
}
}
Some duplication, but I don't see a way around it off the top of my head to allow the compiler to do this:
Vector3 v1 = new Vector3(2, 2, 2);
Vector3 v2 = new Vector3(1, 1, 1);
var v3 = v1 + v2; //Vector3(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y + ", " + v3.Z);
or for other dimensions:
Vector2 v1 = new Vector2(2, 2);
Vector2 v2 = new Vector2(1, 1);
var v3 = v1 + v2; //Vector2(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y); // no "Z" property to output!
What about having an abstract method called Add() that operator+ just acts as a wrapper for? ie, "return v1.Add(v2)". This would also enable you to define interfaces which non-Vector classes can constrain their code to, enabling to perform math-like operations (since generic code can't see/touch operators like +, -, etc for any type).
The only constructor you can code with in a generic method is the default (ie, parameter-less) constructor, which you have to specify in the generic constraints for the method/type.
Five years later I had the exact same problem, only I was calling them Ntuples, not vectors. Here is what I did:
using System;
using System.Collections.Generic;
public class Ntuple{
/*parent class
has an array of coordinates
coordinate-wise addition method
greater or less than in dictionary order
*/
public List<double> Coords = new List<double>();
public int Dimension;
public Ntuple(List<double> Input){
Coords=Input;
Dimension=Input.Count;
}//instance constructor
public Ntuple(){
}//empty constructor, because something with the + overload?
public static Ntuple operator +(Ntuple t1, Ntuple t2)
{
//if dimensions don't match, throw error
List<double> temp = new List<double>();
for (int i=0; i<t1.Dimension; i++){
temp.Add(t1.Coords[i]+t2.Coords[i]);
}
Ntuple sum = new Ntuple(temp);
return sum;
}//operator overload +
public static bool operator >(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]>other.Coords[i]) {return true;}
}
return false;
}
public static bool operator <(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]<other.Coords[i]) {return true;}
}
return false;
}
}//ntuple parent class
public class OrderedPair: Ntuple{
/*
has additional method PolarCoords, &c
*/
public OrderedPair(List<double> Coords) : base(Coords){}
//instance constructor
public OrderedPair(Ntuple toCopy){
this.Coords=toCopy.Coords;
this.Dimension=toCopy.Dimension;
}
}//orderedpair
public class TestProgram{
public static void Main(){
List<double> oneCoords=new List<double>(){1,2};
List<double> otherCoords= new List<double>(){2,3};
OrderedPair one = new OrderedPair(oneCoords);
OrderedPair another = new OrderedPair(otherCoords);
OrderedPair sum1 = new OrderedPair(one + another);
Console.WriteLine(one.Coords[0].ToString()+one.Coords[1].ToString());
Console.WriteLine(sum1.Coords[0].ToString()+sum1.Coords[1].ToString());
bool test = one > another;
Console.WriteLine(test);
bool test2 = one < another;
Console.WriteLine(test2);
}
}
}//namespace ntuples

Casting Type array to Generic array?

The short version of the question - why can't I do this? I'm restricted to .NET 3.5.
T[] genericArray;
// Obviously T should be float!
genericArray = new T[3]{ 1.0f, 2.0f, 0.0f };
// Can't do this either, why the hell not
genericArray = new float[3]{ 1.0f, 2.0f, 0.0f };
Longer version -
I'm working with the Unity engine here, although that's not important. What is - I'm trying to throw conversion between its fixed Vector2 (2 floats) and Vector3 (3 floats) and my generic Vector<> class. I can't cast types directly to a generic array.
using UnityEngine;
public struct Vector<T>
{
private readonly T[] _axes;
#region Constructors
public Vector(int axisCount)
{
this._axes = new T[axisCount];
}
public Vector(T x, T y)
{
this._axes = new T[2] { x, y };
}
public Vector(T x, T y, T z)
{
this._axes = new T[3]{x, y, z};
}
public Vector(Vector2 vector2)
{
// This doesn't work
this._axes = new T[2] { vector2.x, vector2.y };
}
public Vector(Vector3 vector3)
{
// Nor does this
this._axes = new T[3] { vector3.x, vector3.y, vector3.z };
}
#endregion
#region Properties
public T this[int i]
{
get { return _axes[i]; }
set { _axes[i] = value; }
}
public T X
{
get { return _axes[0];}
set { _axes[0] = value; }
}
public T Y
{
get { return _axes[1]; }
set { _axes[1] = value; }
}
public T Z
{
get
{
return this._axes.Length < 2 ? default(T) : _axes[2];
}
set
{
if (this._axes.Length < 2)
return;
_axes[2] = value;
}
}
#endregion
#region Type Converters
public static explicit operator Vector<T>(Vector2 vector2)
{
Vector<T> vector = new Vector<T>(vector2);
return vector;
}
public static explicit operator Vector<T>(Vector3 vector3)
{
Vector<T> vector = new Vector<T>(vector3);
return vector;
}
#endregion
}
"Generic" means "works with any type".
Your example code is not generic, because it only works if and only if T is float.
While you can't convert a Vector2D to a Vector<T&gt, you can, of course, convert a Vector2D to a Vector<float>. Add a Convert method to Vector2D or provide a set of extension methods like this:
public static class VectorExtensions
{
public static Vector<float> ToGenericVector(this Vector2D vector)
{
return new Vector<float>(vector.X, vector.Y);
}
public static Vector2D ToVector2D(this Vector<float> vector)
{
return new Vector2D(vector.X, vector.Y);
}
}
Usage:
Vector<float> v = new Vector<float>(3, 5);
Vector2D v2 = v.ToVector2D();
if T is defined as float, via Vector<T> as Vector<float> then this will work (on a restricted T), but if you just want a local conversion:
var genericArray = new float[3]{ 1.0f, 2.0f, 0.0f };
Of course, this restricts T to being a float anyway (the compiler can't convert just anything to T and knows this), it looks like you should replace T with float in the whole class if that's the case, are you dealing with non-float vectors?
In that case you need something like:
var genericArray = new T[3]{ X, Y, Z };
You cannot imply the type of a generic parameter from within a method.
And, as I stated before, your posted code does not represent a valid usage of Generic type parameters.
The generic parameter is to be defined in the class or method signature.
public class Class1<T>
{
public T[] Method(params T[] args)
{
return args;
}
}
public class Demo
{
public Demo()
{
var c1 = new Class1<float>();
float[] result = c1.Method(1.1f, 2.2f);
}
}
You said:
// This doesn't work
this._axes = new T[2] { vector2.x, vector2.y };
The following works (since everything can be converted to object, and the subsequent conversion from object to T is permitted but may fail at runtime if the types aren’t compatible, or in this case if unboxing cannot be performed):
this._axes = new T[2] { (T)(object)vector2.x, (T)(object)vector2.y };
That said, it makes absolutely no sense to make the class generic.

Categories