0

I'm fairly new to C# and thought I'd start with the tutorials here.

I have done the first 3, and was researching more about C# classes and the various ways you can use them. It then dawned on me that all my code was in one class (MainForm, as I'm using SharpDevelop) and I should try and organise it better. However, when I try to refer to code in other classes, I get a StackOverflowException. I have instantiated the class (e.g. CheckAnswers checkanswers = new checkanswers;), what's going wrong? I can post the code if need be, but my guess is that this is some n00b error that is fairly easy to diagnose.

EDIT:

Code - https://docs.google.com/open?id=0B9vVcIham8NHMGlNaDk3MTZ6ejA

There's quite a bit. This is only the code that I've written myself, not the form config stuff.

7
  • 8
    Please post your code Commented Dec 24, 2012 at 9:02
  • 1
    It maybe a noob error, but we'll mostly be doing educated guesses without any code. My educated guess is you have some recursion going on without a way to break out of it. Commented Dec 24, 2012 at 9:04
  • 2
    We are software engineers not psychics, that is another stackexchange site. Commented Dec 24, 2012 at 9:04
  • @MitchWheat ah thats interesting :) Never ran into to that. Interesting. Commented Dec 24, 2012 at 9:06
  • try CheckAnswers checkanswers = new checkanswers(); instead of your mentioned Commented Dec 24, 2012 at 9:06

3 Answers 3

3

You're making mutual-recursion here.

In MainForm you implicitly call the CheckAnswers constructor at line 23 (it's an initialization of a non-static variable, meaning it'll run when MainForm is constructed).
In CheckAnswers you create a MainForm instance in a similar way (line 193).

That'll cause a stack overflow - MainForm creates a CheckAnswers object which Creates a MainForm object which creates a CheckAnswers object which...

Edit: If you need to make two way communication between the classes (which I advice against in most cases), this won't work. The CheckAnswers object hold a reference to a different instance MainForm, an so does the instance of MainForm. This will simply not work (as well as cause an infinite recursion as see).
One way to do what you want is to send an instance of MainForm to the CheckAnswers constructor, and in line 23 use "this" as the parameter for the constructor and initialize mainform (in CheckAnswers) using that parameter. Something like this:

public partial class MainForm : Form
{
    CheckAnswers checkanswers;
    ...
    public MainForm()
    {
        checkanswers = new CheckAnswers(this);
        ...
    }
}
public class CheckAnswers // Not sure why you inherit MainForm here, but it's not a good idea, as someone already stated
{
    MainForm mainform;

    public CheckAnswers (MainForm main)
    {
        mainform = main;
    }
    ...
}
Sign up to request clarification or add additional context in comments.

3 Comments

OK, but both classes need an object of the other so that they can communicate - how should I go about fixing this?
I've edited my answer to answer your followup question, but I want to emphasize, that this is not a smart way to design code. You're learning C#, so I'd suggest you adopt good design habits at this early stage. OOP has a lot of emphasis on design, so it's as important to understand good design as it is to know the language you use. Think about what you want to create, and ask yourself if MainForm and CheckAnswers really need to "know"/"communicate with" (i.e. hold a reference of) each other
@microbug: Neowizard is right; requiring objects to mutally reference each other is often necessary but to be avoided when possible. Regarding your question: how can both instances reference each other so they can communicate? Go to the real world. Suppose you and a pen pal want to communicate over mail. Somehow they have to get your mail address and you have to get theirs. Think of all the different ways there are to do that, pick one, and write a program that uses an analog of that technique.
1

CheckAnswers class derives from MainForm class. So when you call to constructor of CheckAnswers class, it creates instance of this class with all internal members of base class (MainForm). That's why this line of code is called again:

Line 23: CheckAnswers checkanswers = new CheckAnswers();

And again, instance is created and this line of code is called again and again recursively until StackOverflow exception occurs.

Basically, this code represents the same problem as in your code:

class BaseClass
{
    DerivedClass myObject = new DerivedClass(); // this is a recursive call
}

class DerivedClass : BaseClass
{   
}

3 Comments

Thanks, but it still happens if I change the class from public class CheckAnswers : MainForm to public class CheckAnswers. Is this because I have in the CheckAnswers class MainForm mainform = new MainForm();
Yes, this is a pretty same problem.
Ok, so I understand what the problem is, but I don't see any way of fixing it.
0

To communicate, you should pass as parameter an instance of existing object, not create a new one each time (otherwise there will no be communication between the concrete objects).

So here is an example that represents the idea of what you need to do instead:

public class CheckAnswers
{
    MainForm mainform;
    public CheckAnswers (MainForm  form)
    { 
        this.mainform = form;
    }

   ...
}

In the MainForm class you will have to pass "itself" as parameter to constructor of CheckAnswers like this:

CheckAnswers checkanswers = new CheckAnswers(this);

4 Comments

Thanks, that's just what I needed. When I pass the parameter, should I do MainForm mainform; CheckAnswers checkanswers = new CheckAnswers(mainform);
Oh, you added that as an edit while I was writing the comment. Thanks then! EDIT: Do I have to put CheckAnswers checkanswers = new CheckAnswers(this); inside a method?
Complex (e.g. ones that involve constructor calls) initializations of class members must be inside a method. C# does not guarantee any order on initializations outside of methods, and complex initializations might be affected by order. For example, think what would happen if CheckAnswers had a private static counter, and every time the constructor was called it would assign the current counter value to the new instance and increment. In this case if you had to CheckAnswers instances in MainForm that are initialized outsize a method, you couldn't know which contained which counter value.
I agree that initialization of complex class members should be inside a method (constructor). Though in this example it doesn't matter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.