Vorhandene Eigenschaft oder doppelter Code verwenden?

  • C#

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Vorhandene Eigenschaft oder doppelter Code verwenden?

    Hey,

    ich bin gerade dabei eine Vektorstruktur zu schreiben und habe eine Stilfrage bezüglich des Aufbaus. Im Moment implementiere ich eine Normalize-Methode. Nur frage ich mich, ob es schöner ist zur Berechnung auf die Eigenschaft Length zuzugreifen, die ich in dieser Klasse selbst definiert habe, oder ich den Term zur Berechnung der Länge erneut verwenden soll.

    C#-Quellcode

    1. private double x, y;
    2. public double X
    3. {
    4. get { return x; }
    5. set { x = value; }
    6. }
    7. public double Y
    8. {
    9. get { return y; }
    10. set { y = value; }
    11. }
    12. public double Length
    13. {
    14. get { return Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0)); }
    15. }


    Das ist die Eigenschaft Length von der ich gesprochen habe. Nun ist die Frage ob

    C#-Quellcode

    1. public void Normalize()
    2. {
    3. x = x / Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0));
    4. y = y / Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0));
    5. }


    oder

    C#-Quellcode

    1. public void Normalize()
    2. {
    3. x = x / Length;
    4. y = y / Length;
    5. }


    schöner ist. Ich persönlich halte die zweite Variante zwar für übersichtlicher aber auch unschöner, da ich eine Eigenschaft verwende, die ich erst in dieser Klasse selbst definiert habe.

    LG

    Doppelter Code ist schlechterer Code.
    Nimm das zweite, genau dafür ist die Property doch da.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    @Trade Das hab ich auch gedacht. Aber ich dachte auch, dass die Property nur den Sinn hat die Eigenschaft nach Außen darzustellen um dem Nutzer die Rechnung zu ersparen. Dauert der Aufruf der Length-Property nicht auch noch minimal länger?

    Wieso? Properties kann man doch genauso intern verwenden, um sich das redundante Zeugs zu ersparen.
    Und die Zeit, die es länger dauert, ist derart minimal, das juckt nicht. ;)

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    TheVBTutorialsVB schrieb:

    C#-Quellcode

    1. public double Length
    2. {
    3. get { return Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0)); }
    4. }
    Machst Du

    C#-Quellcode

    1. public double Length
    2. {
    3. get { return Math.Sqrt(x * x + y * y); }
    4. }
    Das geht wesentlich schneller.
    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!
    du siehst daran, dass gute Strukturierung auch der Weg zu sehr guter Performance ist.
    Length an nur einer Stelle berechnen kostet vlt. 10 Prozessortakte, aber nun wirkt jede Performance-Verbesserung gleich vielfach.

    Es ist nicht die absolut beste Performance (die genannten 10 Takte könnt man noch rausholen), aber Das Beste ist der größte Feind des Guten.

    RodFromGermany schrieb:

    return Math.Sqrt(x * x + y * y);
    oder:

    C#-Quellcode

    1. return Math.Sqrt((1 << x) + (1 << y));
    ;D
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

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

    @Radinator

    Quellcode

    1. 'Als Vb.Net Operationen
    2. 1 << 5 ==> 2^5
    3. 3 << 5 ==> 3 * 2^5
    4. 1 >> 5 ==> 1 / (2^5)' als Ganzzahl
    5. 3 >> 5 ==> 3 / (2^5)' als Ganzzahl


    VB.NET-Quellcode

    1. 'In VB.Net ist auch das möglich. Leider nicht in C#
    2. x = x / Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0))
    3. y = y / Math.Sqrt(Math.Pow(x, 2.0) + Math.Pow(y, 2.0))
    4. 'VB
    5. x = x / ((x ^ 2 + y ^ 2) ^ (1 / 2))
    6. y = y / ((x ^ 2 + y ^ 2) ^ (1 / 2))


    Freundliche Grüsse

    exc-jdbi

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

    War ein Versuch wert :|
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Wobei es oftmals stimmt, dass man lieber übersichtlichen Code schreibt als schnellen, darf ich da für eine Vektor-Struktur höflichst wiedersprechen
    @Radinator x*x ist so oder so != 1<<x

    1 << x ist schließlich nur 2^x

    und x*x ist natürlich Math.Pow vorzuziehen.

    msdn.microsoft.com/en-us/libra…lattribute(v=vs.110).aspx
    getter und setter sollte man damit mittels AggressiveInlining gut inlinen lassen können, wobei das bei solch kurzen sowieso passieren sollte, aber dies kann man bei solchen sachen ruhig mit Nachdruck für andere Plattformen machen.
    Allgemein kannst das auf so ziemlich alles der Vektor-struct anwenden.

    Und anstelle Length aus der Property zweimal abzurufen, eben einmal in eine Variable zwischenspeichern, damit das nicht zweimal berechnet wird. Ansonsten ist durch das Inlining, das ganze ziemlich äquivalent zum direkten reinschreiben des Codes - nur Übersichtlicher.

    (Dazu muss man sagen, das inlining in C# hat auch einen kleinen Overhead, da dies nicht zur Compiletime passiert, jedoch ist dieser Overhead spätestens nach dem ersten mal inlining einer Methode nicht mehr vorhanden, da dies nur einmal pro Programmablauf durchgeführt wird.)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    ichduersie schrieb:

    wenn es das schon gibt
    Inzwischen. Ich habs noch nicht.
    Vector2 ist allerdings in Single|Float implementiert, das mag für grafische Anwendungen genügen, für intensivere mathematische Anwendungen genügt das nicht.
    Das hätte Microsoft vielleicht als Template für Double und Single machen können. :/
    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!
    Mal was ganz anderes:
    Vektorstruktur

    C#-Quellcode

    1. public void Normalize()
    2. {
    3. x = x / Length;
    4. y = y / Length;
    5. }


    Veränderbare Wertetypen sind böse!
    Werte in einer List(of) einer private structure ändern
    Ein Vektor ist vom Konzept her ein Wert, kein Objekt.
    Wenn Du von einem Stuhl die Farbe änderst, dann ist es trotzdem noch der selbe Stuhl. Stuhl ist also eine Klasse.
    Wenn Du aber von einem Vektor den X-Wert änderst, dann ist es ein ganz anderer Vektor. Vektor ist also eine Structure.

    Also wenn Du nicht einen sehr guten Grund hast, das so zu machen, solltest Du den Code so abändern, dass die Normalize-Methode einen normalisierten Vektor zurückgibt.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Das aktuelle Numerics gibts nur in nem Nuget-Paket, hat aber natürlich den Vorteil von SIMD(funktioniert bei mir in Mono Nightly noch nicht) und kann somit bei Maschinen ohne Unterstützung einen entsprechend großen Overhead dabei haben.
    Ich bin mir außerdem ziemlich sicher, dass eine sich selbst verändernde struct funktioniert:
    msdn.microsoft.com/en-us/libra…rk.vector2.normalize.aspx
    nicht unbedingt schön, aber darum geht es ja nicht immer, intern macht er trotzdem das richtige daraus und ist dann allemal schöner als

    C#-Quellcode

    1. vec = vec.Normalized();
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    @jvbsl
    Ich finde, es geht genau darum, dass es schön aussieht. Wie gesagt ist ein Vektor ein Wert und kein Objekt.
    Genauso wie Du

    C#-Quellcode

    1. void Foo()
    2. {
    3. double a = ...;
    4. a = a + 10;
    5. a = Math.Sign(a);
    6. }

    schreibst, schreibst Du

    C#-Quellcode

    1. Vector vec = ...;
    2. vec = vec + new Vector(10, 20);
    3. vec = vec.Normalized();


    Wenn es um Performancekritische Situationen geht, kann ich absolut verstehen, dass man das Herumkopieren bei solchen Operationen vermeiden will, aber das sollte man sich genau überlegen.
    Sinnvoller ist es, wenn das Datenmodell diese Wert-Artigkeit widerspiegelt. Denn wenn man das nicht macht, kommen solche Sachen raus:

    C#-Quellcode

    1. Vector[] Normals = ...;
    2. for(int i = 0; i < Normals.Length; i++)
    3. {
    4. Normals[i].Normalize();
    5. }

    Oder dieses Beispiel von Eric Lippert: ericlippert.com/2014/05/21/enumerator-advance/
    (Leider scheint der Link nicht mehr verfügbar zu sein, aber es geht im Grunde genommen darum, dass System.Collections.Generic.List<T>.Enumerator, der IEnumerator<T> für die Liste implementiert, ein veränderbarer Wertetyp ist und es dadurch gerne mal zu unerwarteten Situationen kommt.)
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    jvbsl schrieb:

    x*x ist natürlich Math.Pow vorzuziehen.
    Bezieht sich deine Aussage auf die Tatsache, dass Math.Pow einen double-Wert liefert, der erst wieder (nach Interger) gecastet werden muss?
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell