我希望所有运算符都被覆盖一次,因为它们完全相同。在C ++中我可以定义类Vector {float x,y,z; },并且做typedef Point = Vector,typedef Direction = Vector;在C#中没有等价物(“使用Point = Vector;”很糟糕,因为你必须将它放在你使用的每一个文件中,并且它不是由编译器强制执行的。)
我试图定义3个不同的类并覆盖每个类的运算符,然后进行隐式类型转换,这会使代码运行得更慢等等。
我尝试定义只是Vector,然后点:向量和方向:向量,这样我只编写一次运算符但是我不能做隐式类型转换Point< - >矢量或方向< - >矢量。
我可以简单地定义Vector类并在任何地方使用它,但这会产生模糊性,因为天气变量应该是空间中的位置(Point),空间中的相对位置(Vector)或单位向量(方向)。例如功能:
Vector GetOrthogon(Vector a, Vector b) {
// ....
}
你无法知道它是否期望任何向量或单位向量。在C ++中你可以这样做,为什么不在C#?
注意 :如果可能的话,拥有结构而不是类是理想的。
答案 0 :(得分:10)
数学上,点是矢量。太空中没有绝对点。点被定义为来自某个任意来源的向量。所以,我对点和点之间的差异使用了矢量。
因为方向是单位向量,所以也不需要区分。这就像尝试为整数1和其他整数定义不同的静态类型。所以我使用向量来表示两个方向和点之间的差异。
因此,定义一个Vector类型。它会让你的生活更轻松,因为你会有更少的类和重载的操作符/函数来编写和测试,并且在数学上会更“纯粹”(如果这对你很重要)。
答案 1 :(得分:8)
在纯粹的层面上,我认为Vector
和Point
不相同,代数是:
Point
+ Vector
=> Point
(翻译)Vector
+ Vector
=> Vector
(另外)Point
+ Point
(未定义)我将有2个隐式(它们在逻辑上等价)或显式(否则)转换运算符的不可变结构。我可能没有Direction
结构,但是......我可能在Direction
上有一个Vector
属性,可以将其缩放到单位,但这就是它... < / p>
我已经删除了原始Vector
和Point
以显示相互作用;我没有填写所有Point
(因为它更简单):
public struct Point {
public Point(double x, double y) : this() { X = x; Y = y; }
public double X { get; private set; }
public double Y { get; private set; }
// and more ;-p
}
public struct Vector : IEquatable<Vector> {
public Vector(double x, double y) : this() { X = x; Y = y; }
public Vector AsUnit() {
if (X == 0 && Y == 0) throw new InvalidOperationException();
if (X == 0) return new Vector(0, X > 0 ? 1 : -1);
if (Y == 0) return new Vector(Y > 0 ? 1 : -1, 0);
double sqr = Math.Sqrt((X * X) + (Y * Y));
return new Vector(X / sqr, Y / sqr);
}
public double X { get; private set; }
public double Y { get; private set; }
public static explicit operator Point(Vector vector) {
return new Point(vector.X, vector.Y);
}
public static explicit operator Vector(Point point) {
return new Vector(point.X, point.Y);
}
public override string ToString() {
return "(" + X.ToString() + "," + Y.ToString() + ")";
}
public override int GetHashCode() {
return 17 * X.GetHashCode() + Y.GetHashCode();
}
public override bool Equals(object obj) {
return obj == null ? false : Equals((Vector)obj);
}
public bool Equals(Vector vector) {
return X == vector.X && Y == vector.Y;
}
public static bool operator ==(Vector a, Vector b) {
return a.X == b.X && a.Y == b.Y;
}
public static bool operator !=(Vector a, Vector b) {
return a.X != b.X || a.Y != b.Y;
}
public static Point operator +(Point point, Vector vector) {
return new Point(point.X + vector.X, point.Y + vector.Y);
}
public static Point operator -(Point point, Vector vector) {
return new Point(point.X - vector.X, point.Y - vector.Y);
}
public static Vector operator +(Vector a, Vector b) {
return new Vector(a.X + b.X, a.Y + b.Y);
}
public static Vector operator -(Vector a, Vector b) {
return new Vector(a.X - b.X, a.Y - b.Y);
}
}
答案 2 :(得分:6)
.Net&gt; = 3.0中已有Point
和Vector
个实施。不幸的是System.Windows.Media.Media3D
,因为它们是WPF 3D API的一部分。
这些现有的类确实有一些有用的属性,值得研究(其他人已经提到过):
Point [+|-] Vector = Point
Vector [+|-] Vector = Vector
Point - Point = Vector
Vector
具有执行点和交叉产品的静态方法Vector.Normalise()
和vector.Negate()
按照他们的说法行事也许您可以检查(甚至扩展)这些以供自己使用?
答案 3 :(得分:3)
我建议不要同时使用Vector
和Point
类型。尽管它们在数学上有点不同,但这种区别通常不会在编程上下文中提供任何优势。此外,您可以将点视为从原点到点的位置的矢量。
我强烈建议使用值类型而不是引用类型,因为您通常使用向量,因为您使用实数,因此您需要与float(pass-by-value)相同的语义。如果选择值类型,请记住通常最好使它们不可变。
我还建议不要使用Direction
类型,而更喜欢使用标准化向量。而不是您的三种Vector
,Point
和Direction
类型,只有Vector
就足够了(如果它足够通用)。
至于实施参考,您可以查看XNA's Vector3 structure。
答案 4 :(得分:1)
如果向量是点,而点是向量,则可能它们应该是相同的类(或相同类型的结构)。
或者,如果你想要他们......
...然后使用受保护的构造函数定义基类中的方法和运算符,并将Point和Vector定义为此基类的叶子类,以便它们继承其功能。
如果您不能使用继承等来完成您想要的操作,那么将操作符定义复制并粘贴到几个类中,因为a)它不是维护问题,因为它们不太可能改变b)你说你有一个合理的理由,即“我正在做一个光线跟踪器,因此速度至关重要”。
你可能会说它没关系,因为它们都是向量,但在C ++中你很容易有区别,为什么不用C#?
你也可以在C#中区分:C#支持定义不同的类型等。你可以用C ++做的两件事你不能在C#中使用鸭子模板和全局函数,这可能在这里有用但不是必要的,如果您愿意使用继承或复制并粘贴常用功能。
答案 5 :(得分:1)
我建议将其定义为:
public abstract class VectorBase {
public int X { get; private set; }
public int Y { get; private set; }
public VectorBase(int x, int y) {
this.X = x;
this.Y = y;
}
public VectorBase(VectorBase copy) : this(copy.X, copy.Y) {
// creates a vector with the same x, y
}
public static Vector operator +(VectorBase left, VectorBase right) {
return new Vector(left.X + right.X, left.Y + right.Y);
}
public static Vector operator -(VectorBase left, VectorBase right) {
return new Vector(left.X - right.X, left.Y - right.Y);
}
}
public class Vector : VectorBase {
public Vector(VectorBase v) : base(v) { }
public Vector(int x, int y) : base(x, y) { }
}
public class Point : VectorBase {
public Point(VectorBase v) : base(v) { }
public Point(int x, int y) : base(x, y) { }
public static implicit operator Vector(Point p) {
return new Vector(p);
}
public static implicit operator Point(Vector v) {
return new Point(v);
}
}
public class Direction : VectorBase {
public Direction(VectorBase v) : base(v) { }
public Direction(int x, int y) : base(x, y) { }
public static implicit operator Vector(Direction d) {
return new Vector(d);
}
public static implicit operator Direction(Vector v) {
return new Direction(v);
}
// implementation of *, any other stuff you need
}
注意事项:
immutable
。Vector
,Point
或Direction
,从而产生Vector
。Direction
可以与矢量相乘。implicit operator
更改为explicit operator
来轻松地将其更改为明确可互换。