Zum Inhalt springen
  • 0

C# StackOverflowException


Tician

Frage

Moin!

Ich habe tatsächlich zum ersten mal (außerhalb des Schulunterrichts) mit 2 Klassen zu tun und wollte (auch wenn mein Ausbilder sagt ich bin kein AE und kann globale Variablen benutzen) Variablen mithilfe von Methoden hin und her schieben. Jetzt habe ich mir mit dem was ich gelernt habe und mit dem was ich im Internet gefunden habe etwas zusammen gebastelt das

1. glaube ich keiner mehr versteht

2. sich gar nicht erst kompilieren lässt wegen oben genanntem Fehler

Meine 2 Klassen sind 2 Form-Anwendungen, die eine als Hauptanwendung und die andere quasi als "Settings-Fenster" das über die Menüleiste aufgerufen werden kann. In der Aufrufliste kann ich sehen welche 2 Funktionen sich da verhaken, weiß aber nicht warum weil mir noch das große Bild der Programmierung fehlt.

Hier der Teil der Settings.cs:

public partial class Settings : Form
    {
        string iniText;
        public Settings()
        {
            InitializeComponent();

            Form1 form1 = new Form1(); //das hier wird immer wieder aufgerufen
            iniText = form1.GetIniText();
        }

und das hier von meinem Form1.cs

public partial class Form1 : Form
    {
        //string iniText;
        string iniPathToPDF;
        string iniPathToCSV;
        string iniPathToPCL;
        string iniPrintPDF;
        string iniPrinter;
        string iniPrintserver;
        string iniText;
        Settings form2 = new Settings(); //hier sagt es wird immer wieder aufgerufen
        
        public Form1()
        {            
            InitializeComponent();
            
            try
            {
                ReadIniFile();

                //create Event for Seetings-Close
                form2.FormClosed += Form2_FormClosed;
            }
            catch
            {
                MessageBox.Show("Initialisierung der ini-Datei fehlgeschlagen");
            }

Ich kann meinen Breakpoint nicht da ansetzen wo es auftritt sonst hätte ich das vielleicht irgendwie nachvollziehen können. Die 2 markierten Stellen habe ich eingefügt um damit Funktionen der jeweils anderen Klasse aufzurufen zu können - ist das falsch? Kann sich jemand meiner annehmen und mir das erklären?

 

Grüße

Tician

Bearbeitet von Tician
Link zu diesem Kommentar
Auf anderen Seiten teilen

13 Antworten auf diese Frage

Empfohlene Beiträge

  • 1

Das Problem ist, du rufst die Konstruktoren immer wieder neu auf. Du hast hier ein Zirkelschluss produziert.
Wenn du Settings instanziierst, wird im Konstruktor Form1 instanziiert und Form1 instanziiert wiederrum Settings, usw. usw.

Ich nehme mal an, dass Form1 dein Hauptfenster ist und in Form1 Settings aufgerufen werden soll. 
Settings darf von Form1 nichts wissen. Wozu auch? Und wenn Settings unbedingt Form1 kennen muss, dann musst du Form1 als Abhängigkeit reinreichen.

public Settings(Form mainForm)
{
	InitializeComponent();

	this.mainForm = mainForm
	iniText = form1.GetIniText();
}

Aber selbst das würde ich nicht tun. Ich würde beim Aufruf von Settings den iniText reinreichen:

public Settings()
{
	InitializeComponent();
}

public string IniText
{ 
	get { return this.iniTextTextBox.Text; }
	set { this.iniTextTextBox.Text = value; }
}

Dann würde ich Settings so aufrufen:

Settings settings = new Settings();
settings.IniText = "foo bar";
settings.Show();

Damit ist Settings nicht von Form1 abhängig.. Dies ist jetzt nur eine abgespeckte Version, um das Prinzip etwas zu verdeutlichen. Wenn du es wirklich elegant lösen willst, dann informiere dich über MVP (Model-View-Presenter).
 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1

Ich empfehle dir, dir mal ein C#-Buch zu besorgen und die Grundlagen durchzuarbeiten. Für's erste ist vllt. dieser Link ein Einstieg: https://msdn.microsoft.com/de-de/library/ace5hbzh.aspx

Was grundsätzlich bei einem "new() ..." passiert, ist, dass alle Felder des Objekts auf ihren Standardwert initialisiert werden (ints auf 0, strings auf null, ...) und der Konstruktor ausgeführt wird. Gegebenenfalls werden vor alledem noch die statischen Felder initialisiert und womöglich vorhandene statische Initialisierer ausgeführt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Du legst immer wieder in einem Objekt der einen Klassen ein Objekt der anderen Klasse an. Damit hast du dir die Exception gebaut.

Die Zuweisung im Konstruktur bzw. die Initialisierung des Members werden immer beim Konstruieren eines Objekts ausgeführt.

Nutze statt dessen man einen Setter.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Hallo Tician.

Verstehe ich es richtig, dass du lediglich über Form1 die Settings-Form aufrufen möchtest, welche dann die dort eingegeben Werte zurück an Form1 liefert?
Was macht zudem GetIniText()?
Wo rufst du die Settings-Form auf?

Bearbeitet von Panawr
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Das ist etwas komplizierter, ich versuche mal meinen Gedankengang und etwas mehr Code dazu zu veröffentlichen:

Wenn das Programm gestartet wird läd Form1 Einstellungen aus einer ini-Datei, speichert diese in Variablen und schreibt diese in labels von Form2 (Settings-Fenster) mit der WriteIniToLabels() Methode.

Wenn jetzt aber Form2 über das Menü aufgerufen wird gibt es dort Möglichkeiten die EInstellungen zu ändern. Wenn Form2 geschlossen wird muss Form1 die Einstellungen neu auslesen.

Form1 relevante Ausschnitte:

public partial class Form1 : Form
    {
        //string iniText;
        string iniPathToPDF;
        string iniPathToCSV;
        string iniPathToPCL;
        string iniPrintPDF;
        string iniPrinter;
        string iniPrintserver;
        string iniText;
        Settings form2 = new Settings();
        
        public Form1()
        {            
            InitializeComponent();
            
            try
            {
                ReadIniFile();

                //create Event for Seetings-Close
                form2.FormClosed += Form2_FormClosed;
            }
            catch
            {
                MessageBox.Show("Initialisierung der ini-Datei fehlgeschlagen");
            }
        }

        private void Form2_FormClosed(object sender, FormClosedEventArgs e)
        {
            ReadIniFile();
        }
      
        public void ReadIniFile()
        {
            //ini-Datei lesen
            iniText = File.ReadAllText("settings.ini");
            SetIniText(iniText);

            //PDF und CSV und PCL Pfad lesen und ausgeben
            Regex reg1 = new Regex("(?<=PathToPDF\\=).+");
            Regex reg2 = new Regex("(?<=PathToCSV\\=).+");
            Regex reg4 = new Regex("(?<=PathToPCL\\=).+");
            Match pdfPath = reg1.Match(iniText);
            Match csvPath = reg2.Match(iniText);
            Match pclPath = reg4.Match(iniText);
            iniPathToPDF = Convert.ToString(pdfPath);
            iniPathToCSV = Convert.ToString(csvPath);
            iniPathToPCL = Convert.ToString(pclPath);

            //Write ini-Settings to Form2-Labels
            form2.WriteIniToLabels(iniPathToPDF, iniPathToCSV, iniPathToPCL);

            //Drucker auslesen
            Regex reg5 = new Regex("(?<=Printer\\=).+");
            Regex reg6 = new Regex("(?<=Printserver\\=).+");
            Match printer = reg5.Match(iniText);
            Match printserver = reg6.Match(iniText);
            iniPrinter = Convert.ToString(printer);
            iniPrintserver = Convert.ToString(printserver);

            //Checkbox-status lesen und aktualisieren
            Regex reg3 = new Regex("(?<=PrintPDF\\=).+");
            Match pdfCheck = reg3.Match(iniText);
            iniPrintPDF = Convert.ToString(pdfCheck);
            if (iniPrintPDF == "0")
            {
                checkBox1.Checked = false;
            }
            else
            {
                checkBox1.Checked = true;
            }
        }
        
        string newIniText;

        public void SetIniText(string iniText)
        {
            newIniText = iniText;
        }

        //To get ini from Settings
        public string GetIniText()
        {
            return newIniText;
        }

Form2 relevante Ausschnitte:

public partial class Settings : Form
    {
        string iniText;
        public Settings()
        {
            InitializeComponent();

            Form1 form1 = new Form1();
            iniText = form1.GetIniText();
        }

        //Method for Form1
        public void WriteIniToLabels(string text1, string text2, string text3)
        {
            label1.Text = text1;
            label2.Text = text2;
            label3.Text = text3;
        }

Das ist alles nur Idee und zusammengeschrieben wie es mir in den Sinn kam, ich glaube ein paar Dinge brauch ich gar nicht mehr also sucht da nicht unnötig nach Fehlern die finde ich selbst sobald ich es kompilieren kann (hoffe ich^^). Erstmal muss der StackOverflow raus und ich weiß nicht wie ich es anders machen kann, dazu fehlt mir die Erfahrung.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Bin leider kein riesen Experte in Windows Forms, aber das dürfte doch mit der ersten Methode von Whiz-zarD funktionieren, auch wenn nicht unbedingt super schön.

public Settings(Form mainForm)
{
	InitializeComponent();

	this.mainForm = mainForm
	iniText = this.mainForm.GetIniText();
}

Das Event

private void Settings_FormClosed(object sender, FormClosedEventArgs e)
{
    this.mainForm.ReadIniFile();
}

packst du in die Settings Form.

Beim erzeugen des Objektes

public Form1()
{            
	InitializeComponent();
    form2 = new Settings(this);
	.....
}

musst du dann die Mainform übergeben.

Edit:
Eigentlich müsstest du dann auch nur beim Aufruf der Settings-Form diese erzeugen.

private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
{
   new Settings(this).Show();
}
Bearbeitet von Panawr
Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

@Whiz-zarD

Deine 2. Möglichkeit fand ich bis jetzt am Besten, ich hab versucht sie etwas umzuändern und bin soweit das es gerade so aussieht:

Settings:

public partial class Settings : Form
    {
        //string iniText;
        public Settings()
        {
            InitializeComponent();


            //Form1 form1 = new Form1();
            //iniText = form1.GetIniText();
        }

        //get ini when being called
        public string iniText { get; }

        //Method for Form1
        public void WriteIniToLabels(string text1, string text2, string text3)
        {
            label1.Text = text1;
            label2.Text = text2;
            label3.Text = text3;
        }

Form1:

public partial class Form1 : Form
    {
        //string iniText;
        string iniPathToPDF;
        string iniPathToCSV;
        string iniPathToPCL;
        string iniPrintPDF;
        string iniPrinter;
        string iniPrintserver;
        string iniText;
        Settings form2 = new Settings();

        public Form1()
        {            
            InitializeComponent();
            
            try
            {
                ReadIniFile();
                
                //create Event for Settings-Close
                form2.FormClosed += Form2_FormClosed;
            }
		}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
        {
            ReadIniFile();
        }

Ich habe denke ich verstanden wie ich meine notwendige Variable iniFile von Form1 and Settings übergebe, aber ich wie schiebe ich sie wieder zurück sobald "Settings" geschlossen wird?

 

Was ich jetzt gemacht habe ist quasi die Hälfte übernommen, allerdings sagt mein Programm das Settings.iniText schreibgeschützt ist?

"Für die Eigenschaft oder den Indexer "Settings.iniText" ist eine Zuweisung nicht möglich. Sie sind schreibgeschützt."

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0
vor 6 Minuten schrieb Tician:

Ich habe denke ich verstanden wie ich meine notwendige Variable iniFile von Form1 and Settings übergebe, aber ich wie schiebe ich sie wieder zurück sobald "Settings" geschlossen wird?

Da würde ich dann auf meine Lösung verweisen, falls du sie noch nicht gelesen hast.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 0

Kann ich nochmal etwas zum Verständnis fragen?

Ich dachte immer wenn ich ein Objekt (?) anlege wie zum Beispiel hier

Settings form2 = new Settings();

Was passiert dann genau? Ich dachte das ist wie wenn ich eine Variable anlege, quasi eine leere Hülle.

Wenn ich also von der Form ein Objekt erstelle dann wird was genau gemacht? Alle Objekte und Variablen angelegt/eingelesen hier zwischen den Klammern stehen?

public partial class Settings : Form
    {
		
	}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Diese Frage beantworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...