Best Practice : Gleiche operationen fuer verschiedene Datentypen?

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von exc-jdbi.

    Best Practice : Gleiche operationen fuer verschiedene Datentypen?

    Hey,
    Was sind die besten Ansätze/Pattern für folgendes Szenario:
    Ich bekomme verschiedene Werte für die ich Rechenoperationen durchführen muss. (Sub, Add, Mul, Div, Mod, Shr Shl, Xor usw)
    Die gelieferten Werte konnen allerdings ints, uints, longs, ulongs, floats, doubles, bytes usw sein.
    Wie kann ich verhindern das ich bspw viele Overloads der Rechenmethoden für jeden Datentyp benötige?
    Gibt es da irgendwelche intelligenten Lösungen?
    C# Developer
    Learning C++
    Du kannst ja die Daten Casten bevor du sie an die Methode übergibst.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    Bluespide schrieb:

    witzig
    Wieso?
    Operator muss doch nicht +-*/ sein, sondern z.B. Plus(), Minus(), Mal(), Durch().
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich würde das ungefähr so machen

    Freundliche Grüsse

    exc-jdbi

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Linq.Expressions
    4. Public Module Module1
    5. Public Sub Main()
    6. Dim d1 As Double = 5.0
    7. Dim d2 As Double = 10.0
    8. Dim i161 As Int16 = 5
    9. Dim i162 As Int16 = 10
    10. Dim i321 As Int32 = 5
    11. Dim i322 As Int32 = 10
    12. Dim dd1 As New MOP(Of Double)(d1)
    13. Dim dd2 As New MOP(Of Double)(d2)
    14. Dim resd = dd1 + dd2
    15. Console.WriteLine("{0} + {1} = {2}", dd1.value, dd2.value, resd.value)
    16. Dim i16_1 As New MOP(Of Int16)(i161)
    17. Dim i16_2 As New MOP(Of Int16)(i162)
    18. Dim resi16 = i16_1 + i16_2
    19. Console.WriteLine("{0} + {1} = {2}", i16_1.value, i16_2.value, resi16.value)
    20. Dim i32_1 As New MOP(Of Int32)(i321)
    21. Dim i32_2 As New MOP(Of Int32)(i322)
    22. Dim resi32 = i32_1 + i32_2
    23. Console.WriteLine("{0} + {1} = {2}", i32_1.value, i32_2.value, resi32.value)
    24. Console.ReadLine()
    25. End Sub
    26. End Module
    27. Public Class MOP(Of T)
    28. Public value As T
    29. Public Shared Operator +(ByVal x As MOP(Of T), ByVal y As MOP(Of T)) As MOP(Of T)
    30. Return Add(x.value, y.value)
    31. End Operator
    32. Private Shared Function Add(ByVal x As T, ByVal y As T) As MOP(Of T)
    33. Dim xx = Expression.Parameter(GetType(T), "x")
    34. Dim yy = Expression.Parameter(GetType(T), "y")
    35. Dim body = Expression.Add(xx, yy)
    36. Dim method = Expression.Lambda(Of Func(Of T, T, T))(body, xx, yy).Compile()
    37. Return New MOP(Of T)(method(x, y))
    38. End Function
    39. Public Sub New(ByVal x As T)
    40. Me.value = x
    41. End Sub
    42. End Class


    EDIT:
    Hier hätte ich noch die Mix-Version von oben, wobei ich sie nicht so elegant finde.
    Sie funkst aber.
    MIX

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Linq.Expressions
    4. Public Module Module2
    5. Public Sub Main()
    6. Dim d1 As Double = 5.0
    7. Dim i322 As Int32 = 10
    8. Dim di1 = New MopMix(Of Double, Int32)(d1)
    9. Dim di2 = New MopMix(Of Double, Int32)(i322)
    10. Dim res = di1 + di2
    11. Console.WriteLine("{0} + {1} = {2}", di1.val1, di2.val2, res)
    12. Console.ReadLine()
    13. End Sub
    14. End Module
    15. Public Class MopMix(Of T, U)
    16. Public val1 As T, val2 As U
    17. Public Shared Operator +(ByVal x As MopMix(Of T, U), ByVal y As MopMix(Of T, U)) As Double
    18. Return Add(x.val1, y.val2)
    19. End Operator
    20. Public Shared Function Add(ByVal x As T, ByVal y As U) As Double
    21. Dim xx = Expression.Parameter(GetType(T), "x")
    22. Dim yy = Expression.Parameter(GetType(U), "y")
    23. Dim xd = Expression.Convert(xx, GetType(Double))
    24. Dim yd = Expression.Convert(yy, GetType(Double))
    25. Dim body = Expression.Add(xd, yd)
    26. Dim method = Expression.Lambda(Of Func(Of T, U, Double))(body, xx, yy).Compile()
    27. Return CDbl(method(x, y))
    28. End Function
    29. Private Sub New()
    30. End Sub
    31. Public Sub New(ByVal x As T)
    32. Me.val1 = x
    33. End Sub
    34. Public Sub New(ByVal y As U)
    35. Me.val2 = y
    36. End Sub
    37. End Class

    MIX2

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Linq.Expressions
    4. Module Module3
    5. Public Sub Main()
    6. Dim d1 As Double = 5.0
    7. Dim i322 As Int32 = 10
    8. Dim base1 = New Base(Of Double)(d1)
    9. Dim base2 = New Base(Of Int32)(i322)
    10. Dim mm = New MOPMIX2(Of Double, Int32)(base1)
    11. Dim resbase = mm + base2
    12. Console.WriteLine("{0} + {1} = {2}", base1.value, base2.value, resbase)
    13. 'ODER wenn direkt
    14. resbase = New MOPMIX2(Of Double, Int32)(base1) + base2
    15. Console.WriteLine("{0} + {1} = {2}", base1.value, base2.value, resbase)
    16. Console.ReadLine()
    17. End Sub
    18. End Module
    19. Public Class Base(Of T)
    20. Public value As T
    21. Public Sub New(ByVal val As T)
    22. Me.value = val
    23. End Sub
    24. End Class
    25. Public Class MOPMIX2(Of T, U)
    26. Public val1 As Base(Of T)
    27. Public Shared Operator +(ByVal base1 As MOPMIX2(Of T, U), ByVal base2 As Base(Of U)) As Double
    28. Return Add(base1.val1.value, base2.value)
    29. End Operator
    30. Private Shared Function Add(ByVal x As T, ByVal y As U) As Double
    31. Dim xx = Expression.Parameter(GetType(T), "x")
    32. Dim yy = Expression.Parameter(GetType(U), "y")
    33. Dim xd = Expression.Convert(xx, GetType(Double))
    34. Dim yd = Expression.Convert(yy, GetType(Double))
    35. Dim body = Expression.Add(xd, yd)
    36. Dim method = Expression.Lambda(Of Func(Of T, U, Double))(body, xx, yy).Compile()
    37. Return CDbl(method(x, y))
    38. End Function
    39. Private Sub New()
    40. End Sub
    41. Public Sub New(ByVal x As T)
    42. Me.val1 = New Base(Of T)(x)
    43. End Sub
    44. Public Sub New(ByVal x As Base(Of T))
    45. Me.val1 = x
    46. End Sub
    47. End Class

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „exc-jdbi“ ()

    Mir ist die Frage noch unklar:

    Rikudo schrieb:

    Rechenoperationen durchführen muss. (Sub, Add, Mul, Div, Mod, Shr Shl, Xor usw)
    Die gelieferten Werte konnen allerdings ints, uints, longs, ulongs, floats, doubles, bytes usw sein.
    Wie kann ich verhindern das ich bspw viele Overloads der Rechenmethoden für jeden Datentyp benötige?
    Für die genannten Datentypen ist das nicht dein Problem, weil die genannten Rechenoperationen sind für diese Datentypen ja bereits implementiert.
    (Ausser vlt "Shr Shl" - da weiss ich nicht, was das ist)
    ShiftRight und ShiftLeft.
    gibt theoretisch auch noch RotateRight und RotateLeft....wobei diese Operationen nicht unbeindgt mit floating points funktionieren...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Rotate ist nicht implementiert obwohl oftmals sinnvoll, ist auf x86 sogar bereits ein assembler Kommando. Fehlt interessanterweise auch in C/C++ aber bei einer eigen Implementierung kann C++ das sogar erkennen und zum "rol/ror" befehl optimieren. C# bin ich mir zu 99% sicher kann das leider nicht.(Ich meine optimiert nicht mal / 2 zu >> 1 oder so würde mich also doch sehr wundern), weshalb es für C# also sehr sinnvoll wäre und wenn du jetzt sagst soetwas braucht man nicht, dann sag ich doch z.B. für FFT...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Naja, danke schon mal für die ganzen Beitrage.
    Also soweit mir bekannt ist lasst sich operator overloading nicht für generische Methoden realisieren?
    Die Idee ist folgendes zu vermeiden, viele overloads für den selben Vorgang:

    C#-Quellcode

    1. private int Add(int a, int b){
    2. return a + b;
    3. }
    4. private long Add(long a, long b){
    5. return a + b;
    6. }
    7. private uint Add(uint a, uint b){
    8. return a + b;
    9. }
    10. private float Add(float a, float b){
    11. return a + b;
    12. }


    Ich hatte gedacht vllt kann man hier evtl mit einem Pattern wie dem Factorypattern ansetzen um so etwas elegant zu losen.
    Eine generische Methode allein geht leider nicht.
    Was gitbs denn noch so für Ideen?
    C# Developer
    Learning C++

    Bluespide schrieb:

    Dynamics, wenn es nicht performant sein soll.

    C#-Quellcode

    1. public static T Add<T>(T a, dynamic b) {
    2. return a + b;
    3. }

    Das scheint aber nicht immer zu funktionieren.
    Versuche mal:

    C#-Quellcode

    1. internal class Program
    2. {
    3. private static T Add<T>(T a, dynamic b) {
    4. return a + b;
    5. }
    6. public static void Main(string[] args)
    7. {
    8. byte a = 123;
    9. byte b = 5;
    10. var result = Add(a, b);
    11. Console.WriteLine(result);
    12. }
    13. }


    Quellcode

    1. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?)


    @ErfinderDesRades Was verstehst du an der Frage nicht?
    C# Developer
    Learning C++

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Rikudo“ ()

    Das ist doch ganz normal.
    Die 128 passt nicht in ein Byte (Overflow).
    Durch die Übergabe von a als byte ist T vom Typ byte.
    Also auch der Rückgabetyp.
    a+b ist aber wegen Byte-Überlauf ein int, das du nicht als byte zurückgeben kannst.

    Das würde sicher auch herkömmlich nicht funktionieren:

    C#-Quellcode

    1. byte result = 123 + 5;
    gibt garantiert einen overflow error.
    War (zumindest phasenweise) Blödsinn, ich hatte byte und sbyte verwürfelt.
    Der wahre Grund wurde im Post #18 genannt (byte + byte = int).
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „petaod“ ()

    nein gibt keinen Overflow error, sondern bereits einen compile fehler, weil byte + byte immer int ergit(hier bei const außnahme, weil bereits erkannt wird, dass 128 in byte reinpasst - merke byte ist unsigned und nicht signed), das gilt auch für noch einige operationen mehr. Hängt einerseits mit der stackgröße der elemente für die operationen zusammen, andererseits damit, dass aligned wird und somit optimiert werden kann. Manchmal nicht so toll aber ist halt in C# so...

    Die Frage ist halt wirklich handelt es sich um int/long/double/float mit welchen du das machen willst? Und was erwartest du z.B. bei float und int(z.b. bitshift)
    1 >> 1.4f wird nicht funktionieren...
    Warum nicht die Funktionen schreiben und wenn du wirklich zu faul bist, dann mach ein T4 Template, alles andere ist ugly. Außer du hast natürlich eigene Datentypen welche z.b. ineinander konvertierbar sind...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    gibt garantiert einen overflow error

    Byte.MaxValue ist immer noch 255. 128 passt problemlos in ein Byte. (Du meinst vielleicht den Typ SByte, also eine vorzeichenbehaftete 8-bit Ganzzahl. Da würde 128 nicht mehr reinpassen. Bei sbyte a = 127 + 1; beschwert sich der Compiler: Der Konstantenwert "128" kann nicht in "sbyte" konvertiert werden.)

    Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?)

    Eine Verwendung eines Ausdrucks vom Typ dynamic hat zur Laufzeit das selbe Ergebnis, als hätte der Ausdruck zur Compilezeit den Typ gehabt, den er in dem eintretenden Fall zur Laufzeit hat.
    Und in C# gilt: byte + byte = int. Das Ergebnis wird nicht automatisch zu Byte gecastet.

    Erklärung für die Wissbegierigen

    Das wurde so gehandhabt, weil das das Verhalten des IL-OpCodes "add" wiederspiegelt.

    Dekompiliert man die folgenden Schnipsel, sieht man den Unterschied zwischen VB und C#:

    C#-Quellcode

    1. private static string Add(byte Left, byte Right)
    2. {
    3. var Temp = Left + Right;
    4. return Temp.ToString();
    5. }

    Quellcode

    1. .method private hidebysig static string Add(uint8 Left, uint8 Right) cil managed
    2. {
    3. .maxstack 2
    4. .locals init (
    5. [0] int32 Temp
    6. )
    7. IL_0000: ldarg.0
    8. IL_0001: ldarg.1
    9. IL_0002: add
    10. IL_0003: stloc.0
    11. IL_0004: ldloca.s Temp
    12. IL_0006: call instance string [mscorlib]System.Int32::ToString()
    13. IL_000b: ret
    14. }

    VB.NET-Quellcode

    1. Public Shared Function Add (Left As Byte, Right As Byte) As Byte
    2. Return Left + Right
    3. End Function

    Quellcode

    1. .method public static string Add (uint8 Left, uint8 Right) cil managed
    2. {
    3. .maxstack 2
    4. .locals init (
    5. [0] string Add, // Kann ignoriert werden. Warum diese lokale Variable nicht wegoptimiert wurde ist mir schleierhaft.
    6. [1] uint8 Temp
    7. )
    8. IL_0000: ldarg.0
    9. IL_0001: ldarg.1
    10. IL_0002: add
    11. IL_0003: conv.ovf.u1.un
    12. IL_0004: stloc.1
    13. IL_0005: ldloca.s Temp
    14. IL_0007: call instance string [mscorlib]System.Byte::ToString()
    15. IL_000c: ret
    16. }


    In VB wird das Ergebnis der Addition explizit wieder zu uint8 konvertiert. An der Stelle passiert auch die Prüfung auf Überlauf.
    In C# passiert das nicht. Da bleibt das Ergebnis ein int32 und die Prüfung auf Überlauf passiert garnicht, da unchecked. Aktiviert man checked, wird add.ovf anstelle von add kompiliert. Interessant.
    Mir persönlich gefällt übrigens die Herangehensweise von VB besser, da man sich unnötige Casts spart.


    Wenn byte + byte also zur Compilezeit int ergibt, dann wird das zur Laufzeit von dynamic auch so gehandhabt. Der Ausdruck im Return ist also ein int. Die Funktion gibt aber T zurück, was in Deinem Fall byte ist (vorgegeben durch den Typ ersten Parameters, welcher ja byte ist.) Zur Laufzeit wird also versucht, ein int von einer Funktion zurückzugeben, die ein byte zurückgibt. Das macht sich dann als die genannte Exception bemerkbar.
    Beheben kann man das, indem man explizit zu T castet:

    C#-Quellcode

    1. private static T Add<T>(T a, dynamic b)
    2. {
    3. return (T)(a + b);
    4. }

    Zur Laufzeit wird dann der resultierende int zu byte gecastet, was zur Compilezeit ja problemlos funktionieren würde, und deshalb zur Laufzeit mit dynamic auch funktioniert.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich hatte mal so ein ähnliches Problem, vielleicht hilft das als Referenz.

    Spoiler anzeigen

    C#-Quellcode

    1. internal static class Core
    2. {
    3. internal static bool IsInitialized { get; private set; }
    4. public static List<Type> DataTypes = new List<Type>();
    5. public static void Initialize()
    6. {
    7. if (IsInitialized)
    8. return;
    9. DataTypes.Add(typeof(int));
    10. DataTypes.Add(typeof(short));
    11. DataTypes.Add(typeof(long));
    12. DataTypes.Add(typeof(float));
    13. DataTypes.Add(typeof(double));
    14. IsInitialized = true;
    15. }
    16. public static dynamic Cast(dynamic obj, Type castTo)
    17. {
    18. return Convert.ChangeType(obj, castTo);
    19. }
    20. }


    Spoiler anzeigen

    C#-Quellcode

    1. // Idee vermutlich aus: https://stackoverflow.com/a/3329735/9816636 übernommen gehabt..
    2. public struct Vector3<T> where T : struct,
    3. IComparable,
    4. IComparable<T>,
    5. IConvertible,
    6. IEquatable<T>,
    7. IFormattable
    8. {
    9. public T X { get; set; }
    10. public T Y { get; set; }
    11. public T Z { get; set; }
    12. public Vector3(T x, T y, T z)
    13. : this()
    14. {
    15. Core.Initialize();
    16. X = x;
    17. Y = y;
    18. Z = z;
    19. }
    20. public static Vector3<T> operator +(Vector3<T> a, Vector3<T> b)
    21. {
    22. Vector3<T> output = new Vector3<T>();
    23. foreach (var type in Core.DataTypes)
    24. {
    25. if (type.Equals(typeof(T)))
    26. {
    27. var x0 = Core.Cast(a.X, type);
    28. var x1 = Core.Cast(b.X, type);
    29. var y0 = Core.Cast(a.Y, type);
    30. var y1 = Core.Cast(b.Y, type);
    31. var z0 = Core.Cast(a.Z, type);
    32. var z1 = Core.Cast(b.Z, type);
    33. output.X = Core.Cast(x0 + x1, typeof(T));
    34. output.Y = Core.Cast(y0 + y1, typeof(T));
    35. output.Z = Core.Cast(z0 + z1, typeof(T));
    36. return output;
    37. }
    38. }
    39. return default(Vector3<T>);
    40. }
    41. public static Vector3<T> operator /(Vector3<T> a, Vector3<T> b)
    42. {
    43. Vector3<T> output = new Vector3<T>();
    44. foreach (var type in Core.DataTypes)
    45. {
    46. if (type.Equals(typeof(T)))
    47. {
    48. var x0 = Core.Cast(a.X, type);
    49. var x1 = Core.Cast(b.X, type);
    50. var y0 = Core.Cast(a.Y, type);
    51. var y1 = Core.Cast(b.Y, type);
    52. var z0 = Core.Cast(a.Z, type);
    53. var z1 = Core.Cast(b.Z, type);
    54. output.X = Core.Cast(x1 - x0, typeof(T));
    55. output.Y = Core.Cast(y1 - y0, typeof(T));
    56. output.Z = Core.Cast(z1 - z0, typeof(T));
    57. return output;
    58. }
    59. }
    60. return default(Vector3<T>);
    61. }
    62. public static T operator *(Vector3<T> a, Vector3<T> b)
    63. {
    64. foreach (var type in Core.DataTypes)
    65. {
    66. if (type.Equals(typeof(T)))
    67. {
    68. var x0 = Core.Cast(a.X, type);
    69. var x1 = Core.Cast(b.X, type);
    70. var y0 = Core.Cast(a.Y, type);
    71. var y1 = Core.Cast(b.Y, type);
    72. var z0 = Core.Cast(a.Z, type);
    73. var z1 = Core.Cast(b.Z, type);
    74. return Core.Cast(x0 * x1 + y0 * y1 + z0 * z1, typeof(T));
    75. }
    76. }
    77. return default(T);
    78. }
    79. public static Vector3<T> operator *(T scalar, Vector3<T> a)
    80. {
    81. foreach (var type in Core.DataTypes)
    82. {
    83. if (type.Equals(typeof(T)))
    84. {
    85. var x0 = Core.Cast(a.X, type);
    86. var y0 = Core.Cast(a.Y, type);
    87. var z0 = Core.Cast(a.Z, type);
    88. return new Vector3<T>(Core.Cast(x0 * scalar, typeof(T)), Core.Cast(y0 * scalar, typeof(T)), Core.Cast(z0 * scalar, typeof(T)));
    89. }
    90. }
    91. return default(Vector3<T>);
    92. }
    93. public static Vector3<T> operator /(Vector3<T> a, T scalar)
    94. {
    95. foreach (var type in Core.DataTypes)
    96. {
    97. if (type.Equals(typeof(T)))
    98. {
    99. var x0 = Core.Cast(a.X, type);
    100. var y0 = Core.Cast(a.Y, type);
    101. var z0 = Core.Cast(a.Z, type);
    102. return new Vector3<T>(Core.Cast(x0 / scalar, typeof(T)), Core.Cast(y0 / scalar, typeof(T)), Core.Cast(z0 / scalar, typeof(T)));
    103. }
    104. }
    105. return default(Vector3<T>);
    106. }
    107. public static bool operator <(Vector3<T> a, Vector3<T> b)
    108. {
    109. foreach (var type in Core.DataTypes)
    110. {
    111. if (type.Equals(typeof(T)))
    112. {
    113. var l0 = Core.Cast(a.Length(), type);
    114. var l1 = Core.Cast(b.Length(), type);
    115. return l0 < l1;
    116. }
    117. }
    118. return default(bool);
    119. }
    120. public static bool operator >(Vector3<T> a, Vector3<T> b)
    121. {
    122. foreach (var type in Core.DataTypes)
    123. {
    124. if (type.Equals(typeof(T)))
    125. {
    126. var l0 = Core.Cast(a.Length(), type);
    127. var l1 = Core.Cast(b.Length(), type);
    128. return l0 > l1;
    129. }
    130. }
    131. return default(bool);
    132. }
    133. public static bool operator ==(Vector3<T> a, Vector3<T> b)
    134. {
    135. foreach (var type in Core.DataTypes)
    136. {
    137. if (type.Equals(typeof(T)))
    138. {
    139. var x0 = Core.Cast(a.X, type);
    140. var x1 = Core.Cast(b.X, type);
    141. var y0 = Core.Cast(a.Y, type);
    142. var y1 = Core.Cast(b.Y, type);
    143. var z0 = Core.Cast(a.Z, type);
    144. var z1 = Core.Cast(b.Z, type);
    145. return x0 == x1 && y0 == y1 && z0 == z1;
    146. }
    147. }
    148. return default(bool);
    149. }
    150. public static bool operator !=(Vector3<T> a, Vector3<T> b)
    151. {
    152. return !(a == b);
    153. }
    154. public static double operator ^(Vector3<T> a, Vector3<T> b)
    155. {
    156. var scalar = Core.Cast((a * b) / (Core.Cast(a.Length(), typeof(double)) * Core.Cast(b.Length(), typeof(double))), typeof(double));
    157. return Math.Acos(scalar);
    158. }
    159. public static bool operator |(Vector3<T> a, Vector3<T> b)
    160. {
    161. return a * b == Core.Cast(0, typeof(T));
    162. }
    163. public Vector3<T> TransformBase()
    164. {
    165. return this / Length();
    166. }
    167. public T Length()
    168. {
    169. foreach (var type in Core.DataTypes)
    170. {
    171. if (type.Equals(typeof(T)))
    172. {
    173. var x0 = Core.Cast(X, type);
    174. var y0 = Core.Cast(Y, type);
    175. var z0 = Core.Cast(Z, type);
    176. return Core.Cast(Math.Sqrt(x0 * x0 + y0 * y0 + z0 * z0), typeof(T));
    177. }
    178. }
    179. return default(T);
    180. }
    181. public Vector3<T> Cross(Vector3<T> b)
    182. {
    183. foreach (var type in Core.DataTypes)
    184. {
    185. if (type.Equals(typeof(T)))
    186. {
    187. var x0 = Core.Cast(X, type);
    188. var x1 = Core.Cast(b.X, type);
    189. var y0 = Core.Cast(Y, type);
    190. var y1 = Core.Cast(b.Y, type);
    191. var z0 = Core.Cast(Z, type);
    192. var z1 = Core.Cast(b.Z, type);
    193. return new Vector3<T>(Core.Cast(y0 * z1 - z0 * y1, typeof(T)), Core.Cast(z0 * x1 - x0 * z1, typeof(T)), Core.Cast(x0 * y1 - y0 * x1, typeof(T)));
    194. }
    195. }
    196. return default(Vector3<T>);
    197. }
    198. public override string ToString()
    199. {
    200. return "{" + (X + "").Replace(",", ".") + "," + (Y + "").Replace(",", ".") + "," + (Z + "").Replace(",", ".") + "}";
    201. }
    202. }


    Grüße.

    Post scriptum: Ich weiß nicht was ich mir damals gedacht habe, aber man kann den Iterationsprozess auch umgehen indem man einfach typeof(T) als Parameter in Cast übergibt.
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „φConst“ ()