Optionaler Parameter Konstruktor mit Wert aus Klassenvariable

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

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von MichaHo.

    Optionaler Parameter Konstruktor mit Wert aus Klassenvariable

    Hallo,
    ich arbeite gerade an einer Klassenbibliothek für eine abgespeckte Zeiterfassung.
    Abgespeckt deshalb, weil hier nur Zeiten erfasst werden sollen, damit unsere AT-Mitarbeiter eine Übersicht für sich selbst haben, da sie ja nicht über unser Zeiterfassungssystem laufen.
    Nun möchte ich aber die Bibliothek ein wenig universell gestalten, falls künftig doch mehr daraus werden soll.
    Jetzt ist es so, das unsere bestehenden Mitarbeiter ja eine Personalnummer haben, da diese vom Lohnbüro erstellt wird.
    In meienr Klasse Mitarbeiter möchte ich allerdings die Möglichkeit schaffen einerseits eine Personalnummer beim instanzieren mitzugeben und anderseits, falls keine mitgegeben wird, eine neue freie zu vergeben.

    Erstmal die Klasse Mitarbeiter:
    Spoiler anzeigen

    C#-Quellcode

    1. class Employee : Person
    2. {
    3. int _staffNumber;
    4. int _nextFreeStaffNumber = 0;
    5. TimeRecord _timeRecord;
    6. List<TimeRecord> _timeRecordList = new List<TimeRecord>();
    7. public Employee(string firstname, string lastname, string title, int staffnumber = 0) : base(firstname, lastname, title)
    8. {
    9. if (staffnumber == 0)
    10. { _staffNumber = _nextFreeStaffNumber;
    11. _nextFreeStaffNumber++;
    12. }
    13. else
    14. {
    15. _staffNumber = staffnumber;
    16. }
    17. }
    18. public override int GetStaffNumber()
    19. {
    20. return _staffNumber;
    21. }
    22. public override void CheckIn()
    23. {
    24. if(_timeRecordList.Count != 0 && _timeRecordList.Last().IsCheckedIn)
    25. { throw new ApplicationException("Employee is almost CheckedIn!"); }
    26. _timeRecordList.Add(new TimeRecord());
    27. }
    28. public override void CheckOut()
    29. {
    30. if (_timeRecordList.Count == 0)
    31. { throw new ApplicationException("Employee is not CheckedIn!"); }
    32. _timeRecordList.Last().CheckOut();
    33. }
    34. public TimeSpan TimeRecording()
    35. {
    36. TimeSpan total = new TimeSpan();
    37. foreach (TimeRecord time in _timeRecordList)
    38. {
    39. total += time.Duration;
    40. }
    41. return total;
    42. }
    43. public Double TotalTime()
    44. {
    45. return _timeRecordList.Sum(t => t.Duration.TotalHours);
    46. }
    47. }
    48. }

    So hab ich das im Moment.
    Gibt es in C# nicht die Möglichkeit direkt beim instanzieren, wenn keine personalnummer angegeben wird, direkt die nächstefreie mitzugeben?

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title, int staffnumber = _nextFreeStaffNumber) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = staffnumber;
    4. _nextFreeStaffNumber++;
    5. }

    das funktioniert leider nicht, auch wenn ich _nextFreeStaffNumber als static deklariere
    Ich glaub ich hab da nen Denkfehler...
    Danke Euch
    "Hier könnte Ihre Werbung stehen..."
    Mach eine Überladung und lass die optionalen Parameter, diese müssen nämlich immer auf einen konstanten Wert zeigen.

    Mach also eine Überladung mit personalnummer und eine ohne. Bei der ohne ruf die mit Nummer auf und übergib die nächste nummer.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Hi
    sollte _nextFreeStaffNumber nicht eigentlich statisch sein? Falls ja, solltest du unbedingt Interlocked zum Inkrementieren verwenden (d.h. du musst inkrementieren und vom Rückgabewert 1 abziehen, um das gewünschte Ergebnis zu erhalten), da es sonst nicht threadsicher ist. In deinem Code wäre _nextFreeStaffNumber stets 0 und würde zu eins inkrementiert.

    Viele Grüße
    ~blaze~
    Hi @thefiloe Danke für den Hinweis. (Wald,Bäume)

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = staffnumber;
    4. }
    5. public Employee(string firstname, string lastname, string title) : base(firstname, lastname, title)
    6. {
    7. _staffNumber = _nextFreeStaffNumber;
    8. _nextFreeStaffNumber++;
    9. }

    so sieht es auch deutlich besser aus, danke Dir

    EDIT: Sorry, gerade erst den Post von Dir gesehen @~blaze~
    Hab leider nicht alles verstanden was Du meinst.
    Wenn ich einen neuen Mitarbeiter erstelle, und gebe keine persnummer mit, dann wird doch der Wert aus _nextFreeStaffnumer an _staffNumber übergeben und dann um 1 hochgezählt.... oder nicht?
    Ich werd mir mal ne Konsole in das Projekt hinzufügen zum testen

    EDIT2: muss auch gestehen, hab noch paar Probleme mit dem Schlüßelwort static
    "Hier könnte Ihre Werbung stehen..."

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

    Hallo @~blaze~ hatte meinen Beitrag oben editiert.
    Nu bin ich ganz verwirrt.
    Ich leite ja von Person ab und rufe diesen Konstruktor mit auf um Namen usw. zu übergeben.
    this würde sich doch dann auf die Klasse Employee beziehen und nicht auf Person, oder?
    "Hier könnte Ihre Werbung stehen..."
    Hallo @~blaze~
    Interlocked hab ich mir angeschaut, aber nicht wirklich verstanden.. ;(
    Das mit dem Konstruktor in der Klasse aufrufen mit this() habe ich probiert, aber hat nicht funktioniert.
    Ich verstehe auch nicht ganz was Du damit meinst.
    Wenn ein Mitarbeiter erstellt wird, wird ja der Basis Konstruktor aufgerufen um die Properties der Basisklasse zu belegen damit die Kindklasse Zugriff darauf hat, also vorname, nachname und titel.
    So steht es jedenfalls in meinem C# Buch...
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    Das mit dem Konstruktor in der Klasse aufrufen mit this() habe ich probiert, aber hat nicht funktioniert.

    Das geht so:

    C#-Quellcode

    1. class xyz
    2. {
    3. int X;
    4. int Y;
    5. public xyz() : this(42, -1)
    6. {
    7. }
    8. public xyz(int x) : this(x, -1)
    9. {
    10. }
    11. public xyz(int x, int y)
    12. {
    13. X = x;
    14. Y = y;
    15. }
    16. }
    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!
    Hallo @RodFromGermany
    das wird jetzt kompliziert.

    C#-Quellcode

    1. class Employee : Person
    2. {
    3. int _staffNumber;
    4. static int _nextFreeStaffNumber = 0;
    5. TimeRecord _timeRecord;
    6. List<TimeRecord> _timeRecordList = new List<TimeRecord>();
    7. public Employee(string firstname, string lastname, string title, int staffnumber) : this(firstname, lastname, title)
    8. {
    9. _staffNumber = staffnumber;
    10. }
    11. public Employee(string firstname, string lastname, string title)
    12. {
    13. _staffNumber = _nextFreeStaffNumber;
    14. _nextFreeStaffNumber++;
    15. }

    So ganz verstehe ich es noch nicht. Ich habe ja 2 Konstruktoren in der Kindklasse.
    Wenn ich jetzt nur den 2. Aufrufe, kann ich ja die Properties der Basisklasse nicht setzen...
    Wenn ich beim 2. Konstruktor nochmal this() dahinter schreibe, meckert der Compiler

    EDIT:
    Hier noch die Mutterklasse:
    Spoiler anzeigen

    C#-Quellcode

    1. abstract class Person
    2. {
    3. string _firstName;
    4. string _lastName;
    5. string _title;
    6. public Person(string firstname, string lastname, string title)
    7. {
    8. _firstName = firstname;
    9. _lastName = lastname;
    10. _title = title;
    11. }
    12. public override string ToString()
    13. {
    14. return _firstName + " " + _lastName;
    15. }
    16. public virtual int GetStaffNumber()
    17. {
    18. return -1;
    19. }
    20. public virtual void CheckIn()
    21. { }
    22. public virtual void CheckOut()
    23. { }
    24. }

    "Hier könnte Ihre Werbung stehen..."
    @MichaHo Das ist eine Frage der Herangehensweise.
    Der Konstruktor mit keinem Parameter ruft den Konstruktor mit einem Parameter auf und setzt den Parameter auf den Defaultwert.
    ...
    Der Konstruktor mit n Parametern ruft den Konstruktor mit (n + 1) Parametern auf und setzt den letzten Parameter auf den Defaultwert.
    Der Konstruktor mit der höchsten Anzahl an Parametern ruft den Konstruktor der Basisklasse auf oder setzt die Werte direkt.
    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!
    Irgendwie werd ich das Gefühl nicht los, das this() immer die eigenen Konstruktoren aufruft, also die, der Kindklasse.
    Aber irgendwo muss ich doch den Konstruktor der Basis aufrufen???

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = _nextFreeStaffNumber;
    4. _nextFreeStaffNumber++;
    5. }
    6. public Employee(string firstname, string lastname, string title, int staffnumber) : this(firstname, lastname, title)
    7. {
    8. _staffNumber = staffnumber;
    9. }


    EDIT: warte, ich glaub langsam steig ich dahinter was Du meinst @RodFromGermany....

    hab jetzt:

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = staffnumber;
    4. }
    5. public Employee(string firstname, string lastname, string title) : this(firstname, lastname, title,_nextFreeStaffNumber)
    6. {
    7. _staffNumber = _nextFreeStaffNumber;
    8. _nextFreeStaffNumber++;
    9. }

    Bin mir aber noch unsicher mit dem Defaultwert....
    Also der 2. Konstruktor ruft den ersten auf und setzt dabei staffnumber auf die nächste freie... aber ist das nicht falsch?
    Au mann..... Denkblokade

    "Hier könnte Ihre Werbung stehen..."

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

    @MichaHo So was:

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title) : this(firstname, lastname, title, _nextFreeStaffNumber)
    2. {
    3. }
    4. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    5. {
    6. _staffNumber = _nextFreeStaffNumber;
    7. _nextFreeStaffNumber++;
    8. }
    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!
    OK, hab ich ja fast in meinem Edit auch....ABER....
    Sagen wir ich rufe in deinem Beispiel den 2. Konstruktor auf und gebe 12345 als staffnumber mit.... dann wird doch 12345 garnicht als staffnumber abgelegt, sondern _staffnumber wird mit _nextFreeStuffnumber überschrieben....
    Müsste es nicht daher andersherum sein? (so wie in meinem Edit oben?)

    Vielleicht nochmal als Erklärung: Also wenn ich einen Mitarbeiter erstellen möchte, der bereits eine StaffNumber hat (12345) dann soll diese ja in _staffnumber gespeichert werden. ERST wenn ich einen Mitarbeiter erstelle, der garkeine Staffnumber hat, soll quasi die nächste frei genommen werden und dann in _staffnumber abgelegt werden.
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    dann wird doch 12345 garnicht als staffnumber abgelegt
    Sorry, C&P-Fehler. :whistling:

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title) : this(firstname, lastname, title, _nextFreeStaffNumber)
    2. {
    3. }
    4. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    5. {
    6. _staffNumber = staffnumber;
    7. _nextFreeStaffNumber++;
    8. }
    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!
    Au mann klar.... ich hab deine eingebaute C&P Bremse falsch verstanden.... ;(
    So macht es sinn....
    Frage ist nur, warum steht das in keinem Buch so drinne??? oder les ich die falschen?
    Im Moment hab ich "Andreas Kühnel - C#6 mit Visual Studio 2015"

    EDIT: noch ne andere Frage... OK, 2.... 1. ist der Code meiner Klassen denn dann so OK oder hab ich da noch grobe Schnitzer drinn? 2. wenn ich die _staffnumber nun speichern will, soll ich das dem Anwender überlassen oder sollte man das bereits in die Klasse mit einbauen?
    Ich erweitere gerade die Bibliothek noch um Gäste und Handwerker, wobei Gäste keine Zeiterfassung haben dürfen und Handwerker keine staffnumber bzw. eine staffnumber aus nem eigenen Pool
    "Hier könnte Ihre Werbung stehen..."

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

    MichaHo schrieb:

    warum steht das in keinem Buch so drinne?
    Keine Ahnung, ich kann nicht lesen. :thumbsup: :thumbsup: :thumbsup:
    Die letzten Bücher, die ich mir gekauft habe, zielen auf das Studio 2008 und .NET 4.0.
    Visual C# 2008 von Dirk Louis und Shinja Strasser (Markt+Technik), da steht es im Prinzip so drinne, allerdings ohne eine Basisklasse.
    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!
    Danke Dir @RodFromGermany jetzt kann ich meine anderen Projekte nochmal durchlaufen und dort die Konstruktoren umbauen... :thumbsup:
    Ich schaue mal nach dem von Dir angesprochenen Buch...

    @RodFromGermany warte, ich glaub ich hab doch noch nen Fehler:

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = staffnumber;
    4. _nextFreeStaffNumber++;
    5. }
    6. public Employee(string firstname, string lastname, string title) : this(firstname, lastname, title,_nextFreeStaffNumber)
    7. {
    8. }

    Wenn ich jetzt den 1. Konstruktor 12 mal aufrufe und jedesmal ne Staffnumber mitgebe, dann wird _nextfreestaffnumber ja auch jedesmal hochgezählt...

    Ist es nicht so richtig?

    C#-Quellcode

    1. public Employee(string firstname, string lastname, string title, int staffnumber) : base(firstname, lastname, title)
    2. {
    3. _staffNumber = staffnumber;
    4. }
    5. public Employee(string firstname, string lastname, string title) : this(firstname, lastname, title,_nextFreeStaffNumber)
    6. {
    7. _nextFreeStaffNumber++;
    8. }


    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    Ist es nicht so richtig?
    Denke ich nicht, denn wenn Du den Konstruktor mit 4 Parametern aufrufst, wird dieser Wert nicht erhöht.
    Allerdings hängt das vom Gebrauch dieser Variable ab.
    Wozu wird die denn verwendet?
    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!
    Die Variable _nextFreeStaffnumber soll halt immer die nächste Freie Personalnummer beinhalten, die dann der _staffNumber zugewiesen wird.
    Also wenn ich 5 Mitarbeiter erstelle und keine StaffNumber mitgebe:

    1. M hat dann Staffnumber 0
    2. M bekommt dann Staffnumber 1 usw.
    5. M hat dann StaffNumber 4 und die nächste frei wird auf 5 gestzt.

    Jetzt erstelle ich nen neuen Mitarbeiter, gebe ihm die StaffNumber 12 mit (_nextFreeStaffNumber sollte aber immernoch 5 sein).
    Erstelle ich dann wieder nen neuen Mitarbeiter ohne StaffNumber, bekommt dieser die 5 und _nextFreeStaffnumber wird um 1 erhöht.
    "Hier könnte Ihre Werbung stehen..."
    @MichaHoDann ist Deine Herangehensweise nicht korrekt.
    Wenn Du Dir ne Personalnummer "kaufen" kannst, muss gesichert sein, dass sie disjunkt ist. Um das zu testen, müsstest Du ne statische Funktion bauen, die das tut. Ich gehe davon aus, dass _nextFreeStaffNumber static ist.
    Dann allerdings müsstest Du den Test vor dem Aufruf des Konstruktors machen, denn dieser müsste ne Exception bringen, wenn die Nummer schon da ist.
    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!