nschrag
nschrag

Reputation: 53

In C#, how do field initializers and object initializers interact?

I'm primarily a C++ developer, but recently I've been working on a project in C#. Today I encountered some behavior that was unexpected, at least to me, while using object initializers. I'm hoping someone here can explain what's going on.

Example A

public class Foo {
    public bool Bar = false;
}

PassInFoo( new Foo { Bar = true } );

Example B

public class Foo {
    public bool Bar = true;
}

PassInFoo( new Foo { Bar = false } );

Example A works as I'd expect. The object passed into PassInFoo has Bar set to true. However, in Example B, foo.Bar is set to true, despite being assigned false in the object initializer. What would be causing the object initializer in Example B to be seemingly ignored?

Upvotes: 5

Views: 1238

Answers (4)

Krzysztof Bociurko
Krzysztof Bociurko

Reputation: 4661

I confirm this ugly bug in Unity3d build of Mono (Mono 2.6.5, Unity3d 4.1.2f1, OSX).

It looks like it doesn't like to use the default value for the ValueType, so you can pass a int != 0, (bool)true etc just fine, but passing in the default value like (int)0 or (bool)false ignores it's value.

Proof:

using UnityEngine;
using System.Collections;

public class Foo1 {
    public bool Bar=false;
}

public class Foo2 {
    public bool Bar=true;
}

public class Foo1i {
    public int Bar=0;
}

public class Foo2i {
    public int Bar=42;
}

public class PropTest:MonoBehaviour {

    void Start() {
        PassInFoo(new Foo1 {Bar=true}); // FOO1: True (OK)
        PassInFoo(new Foo2 {Bar=false});/// FOO2: True (FAIL!)
        PassInFoo(new Foo1i {Bar=42});  // FOO1i: 42 (OK)
        PassInFoo(new Foo2i {Bar=0});/// FOO2i: 42 (FAIL!)
        PassInFoo(new Foo2i {Bar=13});/// FOO2i: 13 (OK)
    }

    void PassInFoo(Foo1 f) {Debug.Log("FOO1: "+f.Bar);}

    void PassInFoo(Foo2 f) {Debug.Log("FOO2: "+f.Bar);}

    void PassInFoo(Foo1i f) {Debug.Log("FOO1i: "+f.Bar);}

    void PassInFoo(Foo2i f) {Debug.Log("FOO2i: "+f.Bar);}
}

On a non-unity3d OSX Mono 2.10.11 (mono-2-10/2baeee2 Wed Jan 16 16:40:16 EST 2013) the tests are running fine:

FOO1: True
FOO2: False
FOO1i: 42
FOO2i: 0
FOO2i: 13

EDIT: filled in a bug in unity3d's bugtracker: https://fogbugz.unity3d.com/default.asp?548851_3gh8hi55oum1btda

Upvotes: 5

GiriAzul
GiriAzul

Reputation: 31

I had a similar problem with Unity & Mono.

I got around it by initializing the fields in the constructor and then overwriting with the object initializers.

HOWEVER ! At first this didn't work either. So I replaced the fields with properties with backing fields and it seemed to force expected behaviour.

Upvotes: 3

Kishore Borra
Kishore Borra

Reputation: 269

class Program
{
    static void Main(string[] args)
    {
        PassInFoo( new Foo { Bar = false } );
    }
    public class Foo
    {
        public bool Bar = true;
    }

    public static void PassInFoo(Foo obj)

    {
        Console.WriteLine(obj.Bar.ToString());
        Console.ReadLine();
    }
}

The above code is working fine when verified with Framework 3.5 (false is displayed on the console window).

Upvotes: 2

Thomas
Thomas

Reputation: 64664

The easiest way to see what is happening is to break out your statement into its equivalent if done line-by-line.

Original:

PassInFoo( new Foo { Bar = false } );

Broken out:

var tmp = new Foo();    //Bar initialized to true
tmp.Bar = false;
PassInFoo( tmp );

Upvotes: 3

Related Questions