5 Stimmen

Wie interagieren Feldinitialisierer und Objektinitialisierer in C#?

Ich bin in erster Linie ein C++-Entwickler, aber in letzter Zeit habe ich an einem Projekt in C# gearbeitet. Heute bin ich bei der Verwendung von Objektinitialisierern auf ein zumindest für mich unerwartetes Verhalten gestoßen. Ich hoffe, dass jemand hier erklären kann, was hier los ist.

Beispiel A

public class Foo {
    public bool Bar = false;
}

PassInFoo( new Foo { Bar = true } );

Beispiel B

public class Foo {
    public bool Bar = true;
}

PassInFoo( new Foo { Bar = false } );

Beispiel A funktioniert so, wie ich es erwarten würde. Das an PassInFoo übergebene Objekt hat Bar auf true gesetzt. In Beispiel B wird jedoch foo.Bar auf true gesetzt, obwohl im Objektinitialisierer false zugewiesen wurde. Was könnte dazu führen, dass der Objektinitialisierer in Beispiel B scheinbar ignoriert wird?

5voto

Krzysztof Bociurko Punkte 4448

Ich bestätige diesen hässlichen Fehler in Unity3d Build von Mono (Mono 2.6.5, Unity3d 4.1.2f1, OSX).

Es sieht so aus, als ob es nicht den Standardwert für den ValueType verwenden möchte, also können Sie eine int != 0 , (bool)true usw. problemlos, aber die Übergabe des Standardwerts wie (int)0 o (bool)false ignoriert seinen Wert.

Der Beweis:

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);}
}

Auf einem nicht-unity3d OSX Mono 2.10.11 (mono-2-10/2baeee2 Wed Jan 16 16:40:16 EST 2013) laufen die Tests gut:

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

EDIT: Ich habe einen Bug in den Bugtracker von Unity3d eingetragen: https://fogbugz.unity3d.com/default.asp?548851_3gh8hi55oum1btda

3voto

Thomas Punkte 62314

Der einfachste Weg, um zu sehen, was passiert, ist, Ihre Anweisung in ihre Entsprechung zu zerlegen, wenn Sie sie Zeile für Zeile ausführen.

Original:

PassInFoo( new Foo { Bar = false } );

Ausgebrochen:

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

3voto

GiriAzul Punkte 31

Ich hatte ein ähnliches Problem mit Unity und Mono.

Ich habe es umgangen, indem ich die Felder im Konstruktor initialisiert und dann mit den Objektinitialisierungen überschrieben habe.

ABER! Auch das hat zunächst nicht funktioniert. Also ersetzte ich die Felder durch Eigenschaften mit Backing-Feldern und es schien das erwartete Verhalten zu erzwingen.

2voto

Kishore Borra Punkte 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();
    }
}

Der obige Code funktioniert gut, wenn er mit Framework 3.5 überprüft wird (false wird im Konsolenfenster angezeigt).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X