AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Wozu sind Attribute gut ?

Ein Thema von OlafSt · begonnen am 10. Jul 2013 · letzter Beitrag vom 8. Aug 2013
Antwort Antwort
Seite 2 von 5     12 34     Letzte »    
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#11

AW: Wozu sind Attribute gut ?

  Alt 12. Jul 2013, 12:55
Ich kann hier mal ein Beispiel von mir zeigen:
Code:
    public enum COMM_Command : byte
    {
        #region Paste Bereich

        [CommandInfo(Category.General, "Ping ausführen", PrimaryName = "")]
        PING = 0,
        [CommandInfo(Category.Response, "ACK", PrimaryName = "")]
        NACK = 2,
        [CommandInfo(Category.GetVariable, "Status", Conversion = CommType.Status)]
        REQ_STATE = 6,
        [CommandInfo(Category.GetVariable, "Zyklen")]
        REQ_CYCLES = 7,
        [CommandInfo(Category.GetVariable, "Motor (Promille)", Unit = "‰")]
        REQ_MOTOR_PROMILLE = 8,
        [CommandInfo(Category.GetVariable, "Bremse (Promille)", Unit = "‰")]
        REQ_BRAKE_STATE = 10,
        [CommandInfo(Category.GetSensor, "Encoder (Gegenrad)", Unit = "U/min")]
        REQ_ENCODER_MOTORWELLE = 12,
        [CommandInfo(Category.GetSensor, "Gefahrene Strecke", Unit = "m", Conversion = CommType.thousands)]
        REQ_DRIVEN_DISTANCE = 14,
        [CommandInfo(Category.GetSensor, "Bandsensor (binär)", Unit = "bool")]
        REQ_ROPE_SENSOR_STATE = 16,
        [CommandInfo(Category.GetSensor, "Temperatur", SecondaryName = "Sensor", Unit = "°C")]
        RES_TEMPERATURE = 81,
// ...
        [CommandInfo(Category.SetVariable, "Status", Conversion = CommType.Status)]
        SET_STATE = 135,
        [CommandInfo(Category.SetVariable, "Motor (Promille)", Unit = "‰")]
        SET_MOTOR_PROMILLE = 136,
        [CommandInfo(Category.SetVariable, "Bremse (Promille)", Unit = "‰")]
        SET_BRAKE_PROMILLE = 137,
// ...
        [CommandInfo(Category.Command, "Start", PrimaryName = "")]
        CMD_START = 200,
Das ist jetzt nur ein kleiner Ausschnitt des enum.

Die Attribute ermöglichen mir hier eine GUI ohne Wasserfallertige Fallunterscheidungen. Es gibt eine Combobox wo man die Kategorie auswählen kann ("Variable setzen", "Befehl senden"), die zweite Combobox enthält dann die möglichen Aktionen. Und wenn ein Wert dazu gehört, erscheint darunter eine Textbox.

Das ganze hätte sich auch mit einer Command-Klasse lösen lassen - diese Art hat aber den Vorteil dass der struct (der ein feld mit dem enum enthält) einfach in ein Bytearray konvertiert werden kann. Das ganze kommuniziert nämlich über einen COM-Port mit einem Mikrocontroller. Außerdem ist es einfacher, den enum in den beiden Codebasen gleich zu halten. (Der ganze Inhalt des enums wird inzwischen mit einer Excel-Tabelle generiert - so als Dokumentation)

Die Sache mit den Attributen hat in meinen Augen noch den zusätzlichen Vorteil, dass die Infos im Code "nah beisammen" sind. Fügt man ein Element ohne Attribut hinzu, fällt das sofort auf. (Die Regelmäßigkeit ist unterbrochen) Würde ich die Daten separat in einem Dictionary<COMM_Command, Attribute> ablegen, dann fällt das nicht so flott auf.

Geändert von jfheins (12. Jul 2013 um 13:14 Uhr)
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.366 Beiträge
 
Delphi 10.3 Rio
 
#12

AW: Wozu sind Attribute gut ?

  Alt 12. Jul 2013, 13:06

1) Für die von Dir genannten Anwendungsfälle ORM/Serialisierung ist es eben etwas ungeschickt die
Methode jedes mal zur Laufzeit zusammenzustückeln. Wenn man das ganze gleich richtig macht ist man
eben gleich eine Größenordnung schneller. Attribute sparen da eben nur etwas Tipparbeit (für Code,
den man gerade beim solchen Anwendungsfällen eh vollautomatisch erzeugen kann).
ich persönlich finde, dass die Attribute im Bereich ORM verdammt viel Tipparbeit sparen. z.b. im Bereich der Wertüberprüfung. Da reicht mir dann eine generische Methode die alle Attribute prüft. Und den Wertbereich kann ich direkt beim Property erfassen, dokumentieren und nicht erst im Setter. Wo ich evtl. die Prüfung gar nicht haben will (z.B. beim Laden eines Projektes) und diese wieder kompliziert ausschalten muss.

weiterhin geht es weniger um "Methoden zur Laufzeit zusammenstückeln" sondern eher generische/parametrisierte Methoden zu haben, die mit den Attributen arbeiten, ohne dass ich gleich jedes Property einer Klasse selbst zu einer Klasse erheben muss (was durchaus interessant sein kann, aber manchmal halt nicht machbar ist).

und wegen

3) Man hat für den Code nicht mehr sonderlich viele Compiler zur Auswahl.
selten so gelacht. wie viele Compiler kennst Du denn, die VCL-Code compilieren können? Das ist ja wohl DAS Vendor lock-in schlecht hin....



Grüße
  Mit Zitat antworten Zitat
OlafSt

Registriert seit: 2. Mär 2007
Ort: Hamburg
284 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#13

AW: Wozu sind Attribute gut ?

  Alt 15. Jul 2013, 14:36
Ob man wohl ein simples Beispiel zeigen könnte, die mir Deppen den Nutzen klar aufzeigen ? Die Sache mit dem ENUM weiter oben z.B. ist spannend - es fehlt aber der Fitzel Programmcode, der mir sagt: Jo, det isses. Was ORM ist, ist mir auch ein Rätsel, mag aber daran liegen, das ich nicht studiert hab sondern nur 30 Jahre Praxiserfahrung in den Knochen...
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.851 Beiträge
 
Delphi 11 Alexandria
 
#14

AW: Wozu sind Attribute gut ?

  Alt 15. Jul 2013, 14:39
ORM = Object Relational Mapping

http://de.wikipedia.org/wiki/Objektr...nale_Abbildung
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.763 Beiträge
 
Delphi 11 Alexandria
 
#15

AW: Wozu sind Attribute gut ?

  Alt 18. Jul 2013, 12:48
Ob man wohl ein simples Beispiel zeigen könnte, die mir Deppen den Nutzen klar aufzeigen ? Die Sache mit dem ENUM weiter oben z.B. ist spannend - es fehlt aber der Fitzel Programmcode, der mir sagt: Jo, det isses. Was ORM ist, ist mir auch ein Rätsel, mag aber daran liegen, das ich nicht studiert hab sondern nur 30 Jahre Praxiserfahrung in den Knochen...
Ich schließe mich da mal an. Der Enum Ausschnitt sieht ja erstmal recht "übersichtlich" aus. Eine (beispielhafte) Verwendung des ganzen wäre das Sahnehäubchen.

Sherlock
Oliver
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.487 Beiträge
 
Delphi 7 Enterprise
 
#16

AW: Wozu sind Attribute gut ?

  Alt 18. Jul 2013, 13:12
Hier ist ein schönes Beispiel.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#17

AW: Wozu sind Attribute gut ?

  Alt 18. Jul 2013, 13:34
Übrigens kann man die Geschichte mit den Attributen auch ganz schön übertreiben. Wenn ich mehr Attribute als Methoden habe, wird es für mich fragwürdig, diese in dieser Fülle einzusetzen.

Im Vordergrund sollte übrigens nicht die Ersparnis von Tipparbeit stehen, sondern die Lesbarkeit des Codes. Hier können Attribute -eben weil sie kurz und knackig sind- wirklich dazu beitragen, das der Code lesbarer wird (Stichwort 'ORM').

Ich persönlich finde das gezeigte Beispiel mit den Enums auf den ersten Blick übrigens schlecht lesbar.

Das Beispiel von Union (bzw. sein Link) ist schon schön, verstößt aber (ein wenig) gegen das Prinzip 'Information Hiding', wobei man anmerken muss, das es keinen anderen sinnvollen Platz für Attribute als im Interface-Abschnitt einer Klassendefinition gibt.

Ich persöhnlich gehe mit diesen Dingen eher konservativ um, denn da werkelt für mich zu viel unsichtbarer Code im Hintergrund. Wenn die Aussage hinter einem Attribut nicht klar ist, ist es deplaziert.
  Mit Zitat antworten Zitat
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#18

AW: Wozu sind Attribute gut ?

  Alt 18. Jul 2013, 21:46
Tja, also ich kann gerne mal die Verwendung des enums demonstrieren.

Vorab: Alle Codeschnipsel sind auch auf pastebin zu finden, Code-Highlighting ist ja manchmal schon ganz nett.

Ich hole zuerst mal etwas aus:

Wie oben angedeutet, befinden sich auf dem Formular zwei Comboboxen. Die erste ist für die Kategorie, die zweite für den Typ.

Zu jedem Tupel kann es 1..3 Befehle (enumwerte) geben. So hätte zum Beispiel {"Variable setzen", "Status"} folgende enumwerte zugeordnet:
REQ_STATE = 6, // Status soll abgefragt werden (REQ=Request)
RES_STATE = 70, // Rückmeldung (RES=Response)
SET_STATE = 135, // Status soll gesetzt werden
das Tupel {"Befehl", "Notaus"} hat hingegen nur:
CMD_NOTAUS = 205, // Ein Befehl hat keine zusätzlichen Daten und es kommen auch keine Daten zurück.

Die Kategorie ist übrigens ebenfalls ein enum:
Code:
    public enum Category
    {
        [Description("Allgemein")]
        General,
        [Description("Sensor auslesen")]
        GetSensor,
        [Description("Variable auslesen")]
        GetVariable,
        [Description("Konstante auslesen")]
        GetConstant,
        [Description("Variable setzen")]
        SetVariable,
        [Description("Konstante setzen")]
        SetConstant,
        Response,
        [Description("Befehl")]
        Command
    }
Erläuterung:
Allgemein => Was woanders nicht reinpasste (=PING und Rohdaten verschicken)
Sensor auslesen => Sensoren können abgefragt, aber nicht gesetzt werden
Variablen können ausgelesen und gesetzt werden, ändern sich aber auch mit der Zeit
Konstante => Kann ausgelesen und gesetzt werden, beim Lesen kommt immer der zuletzt geschriebene Wert zurück
Befehle transportieren keine Daten. Der Empfang wird mit einem ACK bestätigt.

Netter Effekt: Die eine Combobox, die die Kategorien enthält, wird mit den Attributen gefüttert. Response steht also im enum drin, aber nicht in der Auswahlliste.

=============================
Nun zur eigentlichen Verwendung: Die Attribute können ja nur mittels Reflection ausgelesen werden. Dazu habe ich eine nette Erweiterungsmethode gebastelt. Nur so geht das typeof(...).ToList das eine Liste mit den passenden Attributwerten zurückgibt.

Der Eventhandler für doe Änderung der Kategorie schaut so aus:
Code:
        private void category_cb_SelectedIndexChanged(object sender, EventArgs e)
        {
            var selected = type_cb.SelectedItem; // Ausgewählten Wert merken

            Category cat = (Category)category_cb.SelectedValue; // Ausgewählte Kategorie
           
// Meine Erweiterungsmethode. Hier steht "Liefere mir bitte anhand des enums 'COMM_Command' eine Liste mit Tupeln {enumwert, Displayname}, bei denen die Kategorie gleich cat ist"
             List<KeyValuePair<Enum, string>> list = typeof(COMM_Command).ToList<CommandInfoAttribute>(x => x.Category == cat, x => x.DisplayName);
// Die Liste dann natürlich gleich in die zweite Combobox schieben
            type_cb.DataSource = list;

// Und falls vorher ein bestimmter Wert ausgewählt war, diesen nach Möglichkeit wieder auswählen.
            if (selected != null)
            {
                string text = ((KeyValuePair<Enum, string>)selected).Value;
                var item = list.FirstOrDefault(x => x.Value == text);
                if (item.Value != null)
                    type_cb.SelectedValue = item.Key;
            }
        }
Ich hoffe die Kommentare machen das Vorgehen deutlich. Hier dann noch der Handler für die Änderung des Typs:
Code:
        private void type_cb_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Einheiten herausfinden
            string name = type_cb.Text;
             List<KeyValuePair<Enum, string>> list = typeof(COMM_Command).ToList<CommandInfoAttribute>(x => x.DisplayName == name, x => x.Unit);

            unit_lbl.Visible = list.Count == 1;
            unit_cb.Visible = list.Count != 1;

// Falls ein Wert geschickt werden soll, bitte die Einheit neben dem Editfeld anzeigen
            // Bei einer Einheit Label benutzen, sonst Combobox
            unit_lbl.Text = list[0].Value;
            if (list.Count > 1)
            {
                unit_cb.DisplayMember = "Value";
                unit_cb.ValueMember = "Key";
                unit_cb.DataSource = list;
            }
// Mit getEnumValue() bekomme ich den enumwert, der durch die aktuelle Auswahl genriert wird.
            CommandInfoAttribute attrib = getEnumValue().GetInfo();

            unit_lbl.Visible = list.Count == 1 && attrib.NeedsPrimaryValue();
            unit_cb.Visible = list.Count != 1 && attrib.NeedsPrimaryValue();

            // Sekundärwert Beschreibung zuweisen und ggf. sichtbar machen
            value2_lbl.Text = attrib.SecondaryName + ":";
            value2_lbl.Visible = attrib.NeedsSecondaryValue();
            value2_txt.Visible = attrib.NeedsSecondaryValue();

            // Bei Auslesen-Befehlen die Werteeingabe verstecken
            value_lbl.Text = attrib.PrimaryName + ":";
            value_lbl.Visible = attrib.NeedsPrimaryValue();
            value_txt.Visible = attrib.NeedsPrimaryValue();
            value_txt.Clear();
        }

        // Welcher Befehl entspricht den aktuellen GUI Einstellungen?
        private COMM_Command getEnumValue()
        {
            var unit = unit_lbl.Visible ? unit_lbl.Text : unit_cb.Text; // Einheit bestimmen
            var enumvalue = typeof(COMM_Command).ToList<CommandInfoAttribute>(x =>
                x.Category == (Category)category_cb.SelectedValue
                && x.DisplayName == type_cb.Text
                && (!x.NeedsPrimaryValue() || x.Unit == unit), x => "").First();
            return (COMM_Command)enumvalue.Key;
        }
Soo, falls ihr das jetzt bis hier durchhabt: Danke dass ihr das gelesen habt Und falls euch jetzt eine bessere Lösung einfällt, nur zu - es hieß nämlich eh "Sag mal, diese Befehle und so, könnte man dafür nicht ne xml Datei machen?"

Das ganze ist natürlich nicht in einer Datei. Falls ihr euch den Code im natürlichen Habitat anschauen wollt, habe ich euch noch eine zip Datei angehängt, in der die meisten Funktionen drin sind. Darin ist auch noch ein bisschen zu sehen, wie das ganze benutzt wird.

Zitat:
Ich persönlich finde das gezeigte Beispiel mit den Enums auf den ersten Blick übrigens schlecht lesbar.
Nicht dass ich jetzt meine Arbeit abwälzen will, aber mich würden andere Ansätz schon interessieren. Der einzige Ansatz auf einem Ähnlichen Abstraktionsniveau war wie folgt: Einen normalen Enum basteln. Danach ein Dictionary<COMM_Command, CCinfo> anlegen. In einem langen Methode dann 212 mal sowas:
Code:
dict.Add(COMM_Command.REQ_APPROACH_BOTTOM_DIST, new CCinfo(Category.GetConstant, "Annäherungsdistanz (unten)") { Unit = "m", Conversion = CommType.thousands });
Hat mich nicht so begeistert
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#19

AW: Wozu sind Attribute gut ?

  Alt 19. Jul 2013, 04:50
Nicht dass ich jetzt meine Arbeit abwälzen will, aber mich würden andere Ansätz schon interessieren.
Darstellung ('Description' Attribut) als Attribut, Parametrierung als Klasse. Zugriff auf die Parameter über eine Dictionary (wie Du schon angedeutet hast).

Vorteil: Skalierbar, d.h. die Parameterklasse kann wachsen, ohne das die Lesbarkeit leidet. Bei der Verwendung von Attributen ist das nicht gegeben, denn irgendwann kleben u.U. über jedem Enum-Wert mehrere Duzend Attribute.

Die Initialisierung des Lookups erfolgt z.B. im statischen Konstruktor. Per Codefolding ist das dann unsichtbar und interessiert eh keine Sau. Die Übersichtlichkeit ist genauso 'toll' wie bei der Verwendung der Attribute.

Letztendlich nimmt sich das nicht viel, aber die Dictionary-Lösung ist erstens ein allgemeingültiges Pattern und zweitens eben (ich wiederhole mich) skalierbar.

Vorteile bei der ausschließlichen Verwendung von Attributen sehe ich nicht.

Ergo (meine Punktezählung)... 2:0 für die altbackene Lösung. Für mich zählt kompakter Code nicht (mehr). Lesbarkeit ist alles.

Frage: Wie lokalisierst (d.h. übersetzt ggfs in andere Sprachen) Du eigentlich die 'Description'-Attribute?

Ach, und zum Code: Wieso verwendest Du keine Viewmodels? (Teeren und Federn sollte man dich )
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.345 Beiträge
 
Delphi 11 Alexandria
 
#20

AW: Wozu sind Attribute gut ?

  Alt 19. Jul 2013, 08:38
Vorteile bei der ausschließlichen Verwendung von Attributen sehe ich nicht.
Die gibt es aber. Attribute haben allgemein den Vorteil, dass sie direkt an den entsprechenden Codeteilen stehen. Wenn man nun dort etwas ändert, sieht man auch sofort, dass das auch geändert werden muss. Insbesondere fällt es sofort auf, wenn das Attribut bei einem neuen Element fehlt bzw. man kann es beim Initialisieren der Daten auch über die RTTI direkt prüfen.

Solange man nur alleine an einem Projekt arbeitet, fällt das nicht so sehr ins Gewicht, da man sich selbst eher dran erinnert, "dass da ja noch was war", aber wenn auch andere daran arbeiten, wissen diejenigen das schlicht nicht immer.

An solchen Stellen dann immer entsprechende Kommentare anzubringen ist zwar möglich, aber auch keine schöne Lösung. Da finde ich es wie auch bei Funktions- und Variablennamen besser, wenn man nur wenige Kommentare braucht, weil man schon aus einem Codeausschnitt alles schnell herauslesen kann.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 5     12 34     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz