Klasseneigenschaft



  • Schönen guten Morgen! 😃

    Ich habe die Aufgabe, eine eigene Klasse zu erstellen, bei der ein negativer Wert nicht erlaubt ist bzw dann eine Meldung auftritt.

    public class Kreis
    {
     private double _radius= 0;  
            public double Radius
            {
                get
                {
                    return _radius;
                }
                set
                {
                    if (value >= 0)
                        _radius= value;
                    else
                        MessageBox.Show("Unzulässiger negativer Wert.");
                }
            }
    }
    

    Hier die Ausgabe

    public Form1()
            {
                InitializeComponent();
    
                Kreis k = new Kreis();
                label1.Text = k.Radius.ToString();
            }
    
            // Ausgabe des Wertes, den der Nutzer eingetragen hat
            private void button1_Click(object sender, EventArgs e)
            {
                label1.Text = textBox1.Text;
            }
    

    Beim Aufruf steht in der Ausgabe zunächst 0. Das stimmt, da ich _radius = 0 initialisiert habe.
    Trage ich nun allerdings in die TextBox z.B. -5 ein, wird dieser Wert genauso ausgegeben, ohne Meldung. Hier meine Frage: Weshalb?

    Danke!
    Gruß Lukas

    P.S.: Ich glaube, ich hätte eine Konsolenanwendung erstellen sollen, aber das sollte doch keinen Unterschied machen, oder?



  • Du weist an keiner Stelle den Wert deiner Klasse zu. Auch sollte die Klasse von sich aus keine Messagebox anzeigen. Das solltest du anders lösen. Das sinnvollste wäre hier entweder eine Exception bei Werten kleiner 0 oder aber einfach das ignorieren des Wertes und beibehalten des alten Wertes.



  • Hab es nun zum Teil geschafft. Statt der MessageBox habe ich eine Exception versucht. Leider mit einer Fehlermeldung (Code).

    public class Kreis
    {
     private double _radius= 0;  
            public double Radius
            {
                get
                {
                    return _radius;
                }
                set
                {
                    if (value >= 0)
                        _radius= value;
                    else
                        throw new Exception("Unzulässiger Wert.");
    // hier erhalte ich nun die Fehlermeldung, Exception wurde nicht behandelt
    // muss ich für die Exception eine eigene Klasse schreiben?
                }
            }
    }
    

    Und ist es richtig, dass wenn der Wert schon beim Aufruf angezeigt werden soll, dass ich dann sowohl beim Aufruf als auch bei der button1_Click Funktion ein neues Objekt erstelle?

    public Form1()
            {
                InitializeComponent();
    
                Kreis k = new Kreis();
                label1.Text = k.Radius.ToString();
            }
    
            // Ausgabe des Wertes, den der Nutzer eingetragen hat
            private void button1_Click(object sender, EventArgs e)
            {
                Kreis k = new Kreis();
                k.Radius = Convert.ToDouble(textBox1.Text);
                label1.Text = k.Kreis.ToString();
            }
    

    Und dann wäre noch die Frage, wie ich auf die Eingabe falscher Zeichen (Buchstaben etc.) reagiere. Wird dies in der Klasse gemacht, oder im restlichen Code, z.B. über Regex?



  • Hallo,

    die Exception muss natürlich noch behandelt werden. Eine Neugenerierung des Objektes ist nicht notwendig. Du kannst und solltest den bestehenden Kreis beibehalten.

    Im folgenden einmal wie ich mir das Vorstelle:

    Kreis.cs

    public class Kreis : INotifyPropertyChanged
    {
        #region Properties
    
        private Double _radius = 0;
        /// <summary>
        /// Gets or sets the radius
        /// </summary>
        public Double Radius
        {
            get { return _radius; }
            set {
                if (value < 0)
                {
                    this._sError = "Der Radius muss größer als 0 sein!";
                    return;
                }
    
                _radius = value;
                this.OnPropertyChanged("Radius");
            }
        }
    
        private string _sError = string.Empty;
        public string Error
        {
            get { return _sError; }
            set { this._sError = value; }
        }
    
        #endregion
    
        #region PropertyChanged
    
        private void OnPropertyChanged(string property)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        #endregion
    }
    

    In deiner Form:

    private Kreis kreis = new Kreis();
    
    public Form1()
    {
        InitializeComponent();
        this.textBox1.DataBindings.Clear();
        this.textBox1.DataBindings.Add("Text", this.kreis, "Radius", true, DataSourceUpdateMode.Never);
    
        this.label1.DataBindings.Clear();
        this.label1.DataBindings.Add("Text", this.kreis, "Radius", true, DataSourceUpdateMode.OnPropertyChanged);
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        this.textBox1.DataBindings["Text"].WriteValue();
        if (!String.IsNullOrEmpty(this.kreis.Error))
        {
            MessageBox.Show(this.kreis.Error);
            this.kreis.Error = string.Empty;
        }
    }
    

    Das ist denke ich fast die einfachste Variante die sich auch leicht in eine Konsolenanwendung übernehmen lässt.

    Beispiel Konsolenanwendung:

    static void Main(string[] args)
    {
        Kreis kreis = new Kreis();
        string input;
    
        do
        {
            Console.WriteLine("Radius eingeben (q => Beenden): ");
            input = Console.ReadLine();
            if (input != "q")
            {
               Double radius = 0;
               if (Double.TryParse(input, out radius))
               {
                  kreis.Radius = radius;
                  if (!String.IsNullOrEmpty(kreis.Error))
                  {
                     Console.WriteLine(kreis.Error);
                     kreis.Error = string.Empty;
                  }
    
                  Console.WriteLine("Neuer Radius ist: " + kreis.Radius);
               }
               else
                  Console.WriteLine("Der eingegebene Wert ist nicht numerisch!");
            }
      } while (input != "q");
    }
    

    Achtung: Beide Lösungen sind so in der Praxis eher unüblich!



  • Also erst mal vielen Dank! Ich versuche aus dem Code zu lernen, so dass ich zukünftig meine Probleme selbst lösen kann! 🙂

    Eine Frage noch:

    inflames2k schrieb:

    Achtung: Beide Lösungen sind so in der Praxis eher unüblich!

    Weshalb??



  • Unüblich daher, dass der Error von außen zurück gesetzt wird. Auch das Handling wie ich die Daten im Forms-Beispiel in das Objekt schreibe ist unüblich hatte für mich aber den praktischen Hintergrund, dass ich kein Casting des in der Textbox befindlichen Wertes durchführen muss.

    Üblich ist bei sowas wirklich eher, eine Exception bei ungültigen Werten zu werfen. Da dies aber ein Schnellbeispiel sein sollte, sollte es so reichen.

    In der Regel ist es auch besser, Werte vor der Zuweisung zu prüfen ob diese gültig sind.



  • Ich habe einige Beispiele versucht zu machen und nachzuvollziehen. Nun habe ich versucht ein eigenes kleines Programm zu machen, welches noch ein paar Fragen für mich aufwirft.

    Meine Fragen habe ich direkt im Code kommentiert.

    public class Rechnung
    {
        #region Eigenschaften
    
    	// Wann string/String; double/Double ... verwenden?
    	// string mit = ""; oder mit string.Empty(); initialisieren?
    	private String _rechnungsnummer;
    	private DateTime _rechnungsdatum;
    	private Double _menge;
    	private Decimal _einzelpreis;
    
        /// <summary>
        /// Get und set der Rechnungsnummer
        /// </summary>
        public String Rechnungsnummer
        {
            get { return _rechnungsnummer; }
            set {
                if (value == "")
                {
                    return;
                }
    
                _rechungsnummer = value;
            }
        }
    
    	/// <summary>
        /// Get und set der Rechungsdatum
        /// </summary>
        public DateTime Rechungsdatum
        {
            get { return _rechnungsdatum; }
            set {
    				_rechnungsdatum = value;
    			}
        }
    
    	/// <summary>
        /// Get und set der Menge
        /// </summary>
        public Double Menge
        {
            get { return _menge; }
            set {
                if (value < 0)
                {
                    return;
                }
    
                _menge = value;
            }
        }
    
    	/// <summary>
        /// Get und set des Einzeplreis
        /// </summary>
        public Decimal Einzelpreis
        {
            get { return _einzelpreis; }
            set {
                if (value < 0)
                {
                    return;
                }
    
                _einzelpreis = value;
            }
        }
    
        /// <summary>
        /// Gesamtpreis einer Position berechnen.
        /// </summary>
    	public Decimal GesamtpreisPosition(double anzahl, decimal einzelpreis)
        {
            _anzahl = anzahl;
            _einzelpreis = einzelpreis;
    
    		// Convert so in einer Methode machen?
    		// Oder besser mit Parse/TryParse?
    		// Wie kann man das sonst lösen, wenn die Variablen unterschiedliche Typen sind?
            decimal gesamtpreis= Convert.ToDecimal(Convert.ToDecimal(_anzahl) * _einzelpreis);
            return gesamtpreis;
        }
    
        #endregion
    }
    
    // Ausgabe der Daten funktioniert
    // Aber ist es "richtig", nur die Methode GesamtpreisPosition(...) dem Objekt rechnung zu übergeben?
    // Oder zunächst jedes item an das Objekt binden: rechnung.Menge = item.Menge?
    // Oder die Daten an den Konstruktor übergeben?
    void RechnungAnzeigen()
    {
    	List<Rechnung> liste = DatenAnzeigen();
        int r = 0;
    
        foreach (var item in liste)
        {
            Rechnung rechnung = new Rechnung();
    
            dataGridView1.Rows.Add();
            dataGridView1["Rechnungsnummer", r].Value = item.RechnungsNummer;
            dataGridView1["Rechnungsdatum", r].Value = item.Datum.ToShortDateString();
            dataGridView1["Menge", r].Value = item.Menge;
            dataGridView1["Einzelpreis", r].Value = item.LieferArtikelBezeichnung;
            dataGridView1["Gesamtpreis", r].Value = rechnung.GesamtpreisPosition(item.Anzahl, item.Einzelpreis);
            r++;
        }    
    }
    
    void RechnungEinlesen()
    {
    	// Wie werden die Daten wieder richtig in eine Liste geschrieben?
    	foreach (DatagridViewRow dr in dataGridView.Rows)
    	{
    		List<Rechnung> liste = new List<Rechnung>();
    		Rechnung rechnungInListe = new Rechnung();
    
    		string col1 = dr.Cells["Rechnungsnummer"].Value.ToString();
    		rechnungInListe.Rechnungsnummer = col1;
    		...
    		liste.Add(rechnungInListe);
    	}
    }
    

Anmelden zum Antworten