61 Stimmen

Was ist der Unterschied zwischen Getter-Only-Auto-Eigenschaften und Ausdruckskörpereigenschaften?

In C# 6 können Sie die Implementierung einer Eigenschaft vereinfachen, indem Sie eine Getter-only-Auto-Eigenschaft verwenden. Wenn beispielsweise die abstrakte Stream-Klasse implementieren würden:

public override bool CanRead { get; } = true;

Jedoch kann man es auch mit einem Ausdrucksbody schreiben, der ebenfalls neu in C# 6 ist:

public override bool CanRead => true;

Was ist der Unterschied zwischen den beiden, und wann sollte ich das eine oder das andere verwenden?

70voto

vcsjones Punkte 134300

Sie sind syntaktischer Zucker für zwei verschiedene Dinge. Ersteres initialisiert ein Backing-Feld und setzt es zum Ausdruck auf der rechten Seite der Zuweisung während der Feldinitialisierung. Letzteres erstellt ein get, das genau das tut, was im Ausdruck steht.

public override bool CanRead { get; } = true;

ist äquivalent zu

private readonly bool __backingFieldCanRead = true;

public override bool CanRead
{
    get
    {
        return __backingFieldCanRead;
    }
}

Dies

public override bool CanRead => true;

ist äquivalent zu

public override bool CanRead
{
    get
    {
        return true;
    }
}

Sie verhalten sich unterschiedlich. Im ersten Fall wird der Wert der Eigenschaft beim Erstellen des Objekts und der Feldinitialisierung gesetzt, im anderen Fall wird der Ausdruck jedes Mal ausgewertet, wenn der Getter der Eigenschaft aufgerufen wird. Im einfachen Fall eines bools ist das Verhalten gleich. Wenn der Ausdruck jedoch Nebenwirkungen verursacht, sind die Dinge anders. Betrachten Sie dieses Beispiel:

class Program
{
    static void Main(string[] args)
    {
        var fooBar1 = new FooBar();
        Console.WriteLine(fooBar1.Baz);
        Console.WriteLine(fooBar1.Baz);
        var fooBar2 = new FooBar();
        Console.WriteLine(fooBar2.Baz);
        Console.WriteLine(fooBar2.Baz);
    }
}

public class FooBar
{
    private static int counter;
    public int Baz => counter++;
}

Hier werden "0, 1, 2, 3" gedruckt. Das statische counter-Feld wird jedes Mal inkrementiert, wenn der Getter der Eigenschaft aufgerufen wird. Jedoch mit einem Eigenschafts-Initializer:

public int Baz { get; } = counter++;

werden dann "0, 0, 1, 1" gedruckt, weil der Ausdruck im Konstruktor des Objekts ausgewertet wird.

4voto

Orace Punkte 6515

In dem Fall, den Sie in unserem Beispiel beschreiben, habe ich früher bevorzugt:

public override bool CanRead { get; } = true;

Aber heute habe ich festgestellt, dass diese Implementierung eine Speicherzuweisung für das Backing Field verursacht. Deshalb kann diese Implementierung 4 Byte sparen: bool CanRead => true;

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