2016-06-12 8 views
-3

Ich möchte Mathematik und das Array überladen und [], um mathematische Operationdouble [] = Operator/(double [] a, double [] b) oder Vector [] = Operator/(Vector [] a, Vector [] b); Warum kann ich das nicht tun? Sogar nur für mich selbst?

zu tun Nach einer Menge auf und zurück, ist die Antwort das Design von C# wird nicht zulassen, dass Sie selbst für sich "überladen" Typen wie Sie können in C++.

Dies ist Gegenstand vieler Diskussionen und könnte in der Zukunft als Feature erscheinen.

Alte c-Programmierer, die sich bewegen (widerwillig zu C#), werden dies verlangen. Ich verlange das.

Zum Beispiel habe ich viele abgeleitete Typen für openGL wie Vertex x. Ich möchte sie hinzufügen, Arrays daraus machen, sie finden. Vererben Sie sie in größere Objekte wie Dreieck oder Quad-Streifen.

Insbesondere möchte ich binäre Operatoren für =/Akkumulatoroperatoren überladen.

Unten, beantworte ich meine Frage. Das Geheimnis ist in C++ können Sie überladen =/TOKEN. =/ist kurz für a = a/b. der Operator =/ist ein Token.

In C# sind es ZWEI Tokens, und Sie können die Zuweisung (=) nicht überladen (verwenden Sie eine implizite Konvertierung oder eine explizite Umwandlung), Sie überladen den Operator als binäres zweites Token.

Zum Beispiel:


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

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

... einfügen in Vertex-Klasse ...


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

Warum kann dies in C# nicht tun?

Weil es so konzipiert ist. Ich müsste eine Klasse Float (als Wrapper für Float) schreiben.

+0

Schritt # 1: 'struct VertexArray {öffentliche Vertex [] Elemente; } 'Schritt # 2: Definieren Sie Operatoren für VertexArray-Objekte. –

+0

Entfernt C++ - Tag, da Ihre Frage C# betrifft (Sie zeigen keinen C++ - Code oder Probleme). –

+0

Was ist 'moderne C#', im Gegensatz zu 'Legacy C#' ??? – ja72

Antwort

0

Sie haben

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

aber

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

kein gültiger Ausdruck ist da für Vertex[] A kein A.x ist.

Schnell Lambda-Lösung:

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

Während letztere new Vertex() Ausdruck auch vereinfacht werden könnte, wenn man den + Betreiber des Vertex Objekt überlasten.

Also, in keiner Weise ist "Is C# mathematisch Analphabeten/Unzählige". Nur ein bisschen von System.Linq benötigt, um es zu einem schönen Ausdruck zu machen.

Dies ist im Grunde eine komponentenweise Vektoraddition, die in C# mit Überlastung des Operators implementiert wird. Siehe auch http://www.dotnetperls.com/zip.

EDIT: Nee, tatsächlich habe ich mich geirrt. Sie können nur Operatoren der umschließenden Klasse überladen, also keine direkten Überladungen für eine Vertex[], es sei denn, Sie deklarieren Vertex[] als eigene Wrapper-Klasse. Aber hier ist ein vollständiger, funktionierender Code mit etwas Überladung und Vektoraddition.

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

    } 
} 
+0

Sehen Sie noch einmal nach echtem funktionierendem C# -Code. –

+0

Nach dem Schlafen auf diesem finde ich diese kompiliert: float [] Zentroid (Vertex [] v) { Int Count = v.Anzahl (); Vertex s = neuer Vertex(); foreach (Vertex vv in v) { s + = vv; } Float [] V = neuer Float [3]; Rückgabe V; } –

+0

öffentlicher statischer Vertexoperator + (Vertex a, Vertex b) { Vertex c = neuer Vertex(); c. x = a. x + b. x; c. y = a. y + b. y; c. z = a. z + b. z; Rückkehr c; } –

1

Hier ist eine ganze Liste für eine Vector3 Klasse, um Ideen zu bekommen, wie Betreiber und Indexer zu implementieren.

[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 

} 

Einige Beispiel für die Verwendung hier:

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

Ich verstehe jetzt das Problem.

Die Implementierung von C# (=) Zuweisung dann (+) Addition als zwei Operatoren, nicht eine einzige Operator (= +) Summierung.

in C++ (=) ist ein Token, das ein unärer Operator ist, die .. überlastet werden kann

in C++ a = + b ist eine Abkürzung für a = a + b

in C#

a = + b expandiert zu a = a + b, aber es ist nicht der Gleichheitsoperator, der überladen werden kann, sondern der Additionsoperator als binärer Operator.

Die Überladungslösung besteht also darin, die Plus-, Minus-, Multiplikations-, Divisions- usw. für die Typen zu überladen, die als binäre Operatoren und nicht als unäre Operatoren erforderlich sind.

Überraschenderweise scheint dies zu kompilieren, um den Schwerpunkt eines Boxel-Typs zu berechnen, der aus einer Anordnung von Kanten besteht, wobei jede Kante zwei Ecken hat. Ich habe noch den Laufzeitcode zu testen, denke aber, dass es jetzt funktioniert.

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

Korrigieren Sie mich, wenn ich falsch liege. Ich bin alt und altersschwach in meiner Programmierung.

Cap Sigma ist der große griechische Buchstabe in der Regel als Summation von unten nach oben auf hochgestellt.

Nun bin ich symbolorientiert und alt und altersschwach bin ich glücklicher.

Ich ziehe meinen Vorwurf zurück, dass C# mathematisch humerieren/analphabetisch ist.

Verwandte Themen