Why it is a StackOverFlow Exception? - c#

Why following code throws StackoverflowException?
class Foo
{
Foo foo = new Foo();
}
class Program
{
static void Main(string[] args)
{
new Foo();
}
}

in Main you create a new Foo object, invoking its constructor.
inside Foo constructor, you create a different Foo instance invoking again Foo constructor.
This lead to infinite recursion and end with a StackOverflow exception

Well, let´s see:
Program runs main which executes new Foo();;
new Foo() creates new Foo instance, including Foo foo field
Foo foo = new Foo();executes new Foo (go to step 2)

Related

Static constructors and field initialization order in C#

This sample from C# in a Nutshell says it writes 0 followed by 3 due to "the field initializer that instantiates a Foo executes before X is initialized to 3".
class Program {
static void Main() { Console.WriteLine (Foo.X); } // 3
}
class Foo
{
public static Foo Instance = new Foo(); //static field 1
public static int X = 3; //static field 2
Foo() => Console.WriteLine (X); // 0
}
My question is, why does this not go into an infinite recursion due to static field 1 which makes a new Foo (which makes a new Foo, which makes a new Foo, etc.)?
Let's have a look at what's going on. BeforeFoo class addressing static fields must be
initialized.
class Program {
static void Main() {
// Before Foo class is addressed (here Foo.X), Foo must be initialized
Console.WriteLine(Foo.X);
}
}
.Net will do it in order they are mentioned in the class declaration:
class Foo
{
// Will be run first
public static Foo Instance = new Foo();
// Will be run second
public static int X = 3;
Foo() => Console.WriteLine(X);
}
So far so good, Instance start its initialization
public static Foo Instance = new Foo();
constructor Foo() called which prints X: Foo() => Console.WriteLine (X); note,
that since X has not been initialized, 0 will be printed.
X will be initialized, it's now 3
Initialization is completed now, and .Net is ready to adddress Foo class
Console.WriteLine(Foo.X);
and 3 will be printed (note the 2nd step of the initialization)
Static fields and properties are shared across all instances of a class, and get initialized in a special constructor called .cctor that gets called when the class is first referenced.
So the compiled code is something similar to
class Foo
{
public static Foo Instance;
public static int X;
.cctor() {
Instance = new Foo();
X = 3;
}
Foo() => Console.WriteLine (X);
}
The call flow would be Foo::.cctor -> Foo::Foo() -> Foo:get_X().
So there is no recursion, but X will have its default value when .cctor is called.

Why I'm getting StackOverflowException?

I'm getting StackOverflowException when I run below program. My doubt is how this program recursively calling each classes(ArrayTest1, ArrayTest2) fields without executing constructor method?
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var arraryTest = new ArrayTest1();
}
}
public class ArrayTest1
{
ArrayTest2 arrayTest2 = new ArrayTest2();
public ArrayTest1()
{
Console.WriteLine($"{nameof(ArrayTest1)} Class Contructor Executed");
}
}
public class ArrayTest2
{
ArrayTest1 arrayTest1 = new ArrayTest1();
public ArrayTest2()
{
Console.WriteLine($"{nameof(ArrayTest2)} Class Contructor Executed");
}
}
Because you create an infinite chain of ArrayTest1 -> ArrayTest2 -> ArrayTest1 -> ArrayTest2 -> ...
To understand why you are not getting any output, see C# constructor execution order
Important steps in your case (no inheritance involved):
Member variables are initialized to default values
Variable initializers are executed
The constructor bodies are executed
You never reach constructor bodies, as the stack overflow happens in variable initializer
Because when you do this:
new ArrayTest1()
You are creating an instance of ArrayTest1. Which does this:
ArrayTest2 arrayTest2 = new ArrayTest2();
This creates an instance of ArrayTest2. Which does this:
ArrayTest1 arrayTest1 = new ArrayTest1();
This creates an instance of ArrayTest1. Which does this:
ArrayTest2 arrayTest2 = new ArrayTest2();
This creates an instance of ArrayTest2. Which does this:
ArrayTest1 arrayTest1 = new ArrayTest1();
This creates an instance of ArrayTest1...
And so on, indefinitely.
It's not clear what your goal is with the code. But what is clear is that your objects can't mutually depend on one another this way because the simple act of creating an instance of the object results in an infinite recursion.
Given only the code shown, the solution is to simply remove those mutually-dependent fields from the classes, since nothing ever uses them anyway:
public class ArrayTest1
{
public ArrayTest1()
{
Console.WriteLine($"{nameof(ArrayTest1)} Class Contructor Executed");
}
}
public class ArrayTest2
{
public ArrayTest2()
{
Console.WriteLine($"{nameof(ArrayTest2)} Class Contructor Executed");
}
}

What is the lifetime of a property with only a getter

Lets assume I instantiated MyClass. Does my Foo property have a reference at this point or is it null? Also what happens after I call UseFoo() and exit the scope? Did I dispose Foo or just foo?
public class MyClass
{
private readonly string param;
private IDisposable Foo => new Foo(param);
public MyClass(string param)
{
this.param = param;
}
public void UseFoo()
{
using var foo = Foo;
// use foo
}
}
Q: Does my Foo property have a reference at this point or is it null?
A: No, because the property does not have a backing field, aka state.
Instead, every time you read the value of Foo, you will construct a new instance of the Foo type and return that.
As #juharr so nicely put it in their comment, it is a property but behaves like a method.
Q: Also what happens after I call UseFoo() and exit the scope? Did I dispose Foo or just foo?
A: You disposed the single object that you got from reading the Foo property and stored in the foo local variable.
Since the Foo property does not actually have state, you only disposed the object that was constructed for you when you read the Foo property.
The next time you read the Foo property you will get a new instance.
I find it helpful to mentally translate => to "returns". It is an active operation, not a passive assignment. So in your case, I would read it as "Foo returns a new foo of param".
When it comes to properties,
private IDisposable Foo => new foo(param);
is equivalent to
private IDisposable Foo
{
get { return new foo(param); }
}

Object initialized in other class's method isn't referenced by calling method in C#

I have a class where I declare an object, but don't initialize the object. Then I pass the object to a method in another class for initialization. What I expect to happen is that the object in the calling class will now have a reference to the initialized object, but instead it is null.
Here is an example of what I mean:
class MainClass
{
ObjectA foo;
OtherClass.InitializeObjectA(foo);
// why is foo null over here?
}
class OtherClass
{
public static void InitializeObjectA(ObjectA device)
{
device = new ObjectA();
}
}
My problem is that device when I try to use foo after calling InitializeObjectA() it is still pointing to null! If I change InitializeObjectA() to out ObjectA device it works. Can anyone explain why this is needed?
If you want this to work, you need to pass by reference:
public static void InitializeObjectA(ref ObjectA device)
{
Or:
public static void InitializeObjectA(out ObjectA device)
{
Without that, InitializeObjectA sets the device parameter to a new ObjectA(), but that will not affect the caller, because, by default, references are passed by value.
Note that, if you're just trying to initialize, returning an instance instead of void is often a better way to handle this:
public static ObjectA InitializeObjectA()
{
return new ObjectA();
}
This avoids the need to use ref or out passing.
A class is a reference type, you pass the address of foo as parameter (copy), within you change the copy, but the new address won't be set back to the original foo. This will only be done with the out or ref keyword.
The simplest way to create the instance of ObjectA named foo is to return the instance to assign to the variable
class MainClass
{
ObjectA foo = OtherClass.InitializeObjectA();
}
class OtherClass
{
public static ObjectA InitializeObjectA()
{
return new ObjectA();
}
}
Why not just have the Initialize method return the created object?
class MainClass
{
var foo = OtherClass.InitializeObjectA(foo);
}
class OtherClass
{
public static ObjectA InitializeObjectA(ObjectA device)
{
return new ObjectA();
}
}
From what I understand, the C# compiler doesn't actually initialize variables for you like that. I'm not even able to compile this code in Visual Studio 2010, because it's an error to pass an uninitialized parameter to a function.
You want:
ObjectA foo = null;
Which is I think what you're trying to do anyway, C# just doesn't do it for you as it would in Java. This still doesn't get the behavior I think you're trying to achieve though, which is probably best accomplished by refactoring your code to something like
ObjectA foo = InitializeObjectA()
public static ObjectA InitializeObjectA(){
return new ObjectA();
}
Alternately, you can use pass by reference, where you pass a reference (or pointer if you're familiar with it) to the function, so changes made to that reference are reflected outside the scope of your function.
That's because when you do
device = new ObjectA();
you are setting the object to a new one, with a different reference in memory.
You should do something like:
class MainClass
{
ObjectA foo = OtherClass.InitializeObjectA(foo);
}
class OtherClass
{
public static ObjectA InitializeObjectA(ObjectA device)
{
return = new ObjectA();
}
}
or instead
class MainClass
{
ObjectA foo = null;
OtherClass.InitializeObjectA(out foo);
}
class OtherClass
{
public static void InitializeObjectA(out ObjectA device)
{
device = new ObjectA();
}
}
More information about why this happens can be found here.

Global Objects when using Mono with MonoMac

How do I declare global instances of objects?
When using C# and .NET I would do something like this:
public static program {
public static Foo MyFoo = new Foo();
static void main() {
MainForm = new MainForm(MyFoo);
}
}
however with Mono/MonoMac the main function calls NSApplication.Main and doesn't directly create any windows. How would I pass an instance of MyFoo to the main window?
Note: I am trying to avoid any references to MainClass in my windows/window controllers as that creates a tight coupling. I want to reuse the window classes in other situations hence the desire for loose coupling.
Is what I want possible with MonoMac?
thanks, Andy
Use a singleton ? Your code would then look like:
public class Foo {
public static Foo Global = new Foo ();
public Foo () { }
// rest of Foo logic
}
public class Program {
static void Main () {
MainForm = new MainForm (Foo.Global);
}
}

Categories