double[]=运算符/(double[]a,double[]b)或Vector[]=运算符(Vector[]a,Ve



我想重载数学和数组,并[]进行数学运算

经过大量的反复,答案是c#的设计不会让你过载,即使是像在c++中那样为自己的"内置"类型。

这受到了很多争论,并可能在未来成为一个特色。

老c程序员(不情愿地转向c)会要求这样做。我要求这样做。

例如,我有很多openGL的派生类型,比如Vertex x。我想添加它们,制作它们的数组,找到它们。将它们继承到更大的对象中,例如三角形或四边形条纹。

具体来说,我想重载=/累加器运算符的二进制运算符。

下面,我回答我的问题。秘密是在C++中,您可以重载=/TOKEN。=/是a=a/b的缩写。运算符=/是一个标记。

在c#中,它是两个标记,并且不能重载赋值(=)(使用隐式转换或显式强制转换)运算符作为二进制第二令牌。

例如:


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;
}
}
}

插入到Vertex类中。。。


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;
}
}

为什么在c#中不能做到这一点?

因为它是这样设计的。我必须编写一个类Float(作为Float的包装器)。

以下是Vector3类的完整列表,以便了解如何实现运算符和索引器。

[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
}

这里的一些用法示例:

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);
}

我现在理解了这个问题。

c#(=)赋值然后(+)加法的实现是两个运算符,而不是单个运算符(=+)求和。

在c++中(=)是一个标记,它是一个可以重载的一元运算符。。

在c++a=+b是a=a+b 的简写

在c#中

a=+b扩展为a=a+b,但可以重载的不是相等运算符,而是作为二进制运算符的加法运算符。

因此,重载的解决方案是重载作为二进制运算符而非一元运算符所需的类型的加号、减号、乘法、除法等。

令人惊讶的是,这似乎是为了计算Boxel类型的质心而编译的,Boxel类型由一组边组成,每条边都有两个顶点。我还没有测试运行时代码,但我认为它现在可以工作了。

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;
}

如果我错了,请纠正我。我的编程方式又老又衰。

Cap Sigma是一个大的希腊字母,通常从楼下的下标到楼上的上标作为总和。

现在有了象征意识,又老又衰,我更快乐了。

我收回了我对c在数学上不识字的指责。

您有

public static Vertex[] operator+(Vertex[] A, Vertex[] B)
{
return new vertex[] { A.x+B.x, A.y+B.y, A.z+B.z };
}

但是

return new vertex[] { A.x+B.x, A.y+B.y, A.z+B.z };

不是有效的表达式,因为对于CCD_ 2不存在CCD_。

快速lambda解决方案:

return A.Zip(B, (v1, v2) => new Vertex(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z)).ToArray();

而如果重载Vertex对象的+运算符,也可以简化后一个new Vertex()表达式。

因此,决不是"c在数学上是文盲/数不胜数"。只需要一点点System.Linq就可以使它成为一个很好的表达。

这基本上是用运算符重载在C#中实现的分量矢量加法。另请参阅http://www.dotnetperls.com/zip.

编辑:不,事实上我错了。只能重载封闭类中的运算符,因此除非将Vertex[]声明为自己的包装类,否则不能直接重载Vertex[]。但这里有一个完整的工作代码,带有一些运算符重载和向量添加。

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());
}
}

相关内容

最新更新