webentwicklung-frage-antwort-db.com.de

Was ist die => Zuweisung in C # in einer Eigenschaftssignatur

Ich bin auf einen Code gestoßen, der besagte

public int MaxHealth => 
         Memory[Address].IsValid ? 
         Memory[Address].Read<int>(Offs.Life.MaxHp) : 
         0;

Jetzt bin ich einigermaßen mit Lambda-Ausdrücken vertraut. Ich habe es einfach noch nicht so gesehen.

Was wäre der Unterschied zwischen der obigen Aussage und

public int MaxHealth  = x ? y:z;
206
Mike

Was Sie sehen, ist ein ausdrucksstarkes Mitglied kein Lambda-Ausdruck.

Wenn der Compiler auf ein Element mit ausdrucksstarker Eigenschaft trifft, konvertiert er es im Wesentlichen in einen Getter wie diesen:

public int MaxHealth
{
    get
    {
        return Memory[Address].IsValid ? Memory[Address].Read<int>(Offs.Life.MaxHp) : 0;
    }
}

(Sie können dies selbst überprüfen, indem Sie den Code in ein Tool namens TryRoslyn pumpen.)

Ausdrucksstarke Mitglieder sind - wie die meisten C # 6-Features - nur syntaktischer Zucker . Dies bedeutet, dass sie keine Funktionen bieten, die mit vorhandenen Funktionen sonst nicht möglich wären. Stattdessen ermöglichen diese neuen Funktionen die Verwendung einer aussagekräftigeren und prägnanteren Syntax

Wie Sie sehen, verfügen ausdrucksstarke Member über eine Reihe von Verknüpfungen, die Eigenschaftsmember kompakter machen:

  • Es ist nicht erforderlich, eine return -Anweisung zu verwenden, da der Compiler darauf schließen kann, dass Sie das Ergebnis des Ausdrucks zurückgeben möchten
  • Es ist nicht erforderlich, einen Anweisungsblock zu erstellen, da der Text nur ein Ausdruck ist
  • Das Schlüsselwort get muss nicht verwendet werden, da es durch die Verwendung der Ausdruckssyntax impliziert wird.

Ich habe den letzten Punkt fett gedruckt, weil er für Ihre eigentliche Frage relevant ist, die ich jetzt beantworten werde.

Der Unterschied zwischen...

// expression-bodied member property
public int MaxHealth => x ? y:z;

Und...

// field with field initializer
public int MaxHealth = x ? y:z;

Ist das gleiche wie der Unterschied zwischen ...

public int MaxHealth
{
    get
    {
        return x ? y:z;
    }
}

Und...

public int MaxHealth = x ? y:z;

Welches - wenn Sie Eigenschaften verstehen - sollte offensichtlich sein.

Um es klar zu machen: Die erste Auflistung ist eine Eigenschaft mit einem Getter unter der Haube, die jedes Mal aufgerufen wird, wenn Sie darauf zugreifen. Die zweite Auflistung ist ein Feld mit einem Feldinitialisierer, dessen Ausdruck nur einmal ausgewertet wird, wenn der Typ instanziiert wird.

Dieser Unterschied in der Syntax ist eigentlich ziemlich subtil und kann zu einem "gotcha" führen, das von Bill Wagner in einem Beitrag mit dem Titel "AC # 6 gotcha: Initialization vs. Expression Bodied Members" beschrieben wird. .

Mitglieder mit Ausdruck sind Lambda-Ausdrücke - wie , aber keine Lambda-Ausdrücke. Der grundlegende Unterschied besteht darin, dass ein Lambda-Ausdruck entweder zu einer Delegateninstanz oder zu einem Ausdrucksbaum führt. Mitglieder mit Ausdruck sind nur eine Anweisung an den Compiler, eine Eigenschaft hinter den Kulissen zu generieren. Die Ähnlichkeit (mehr oder weniger) beginnt und endet mit dem Pfeil (=>).

Ich werde auch hinzufügen, dass ausdrucksstarke Mitglieder nicht auf Eigenschaftsmitglieder beschränkt sind. Sie arbeiten an all diesen Mitgliedern:

  • Eigenschaften
  • Indexer
  • Methoden
  • Betreiber

Hinzugefügt in C # 7.

Sie arbeiten jedoch nicht mit diesen Mitgliedern:

  • Geschachtelte Typen
  • Veranstaltungen
  • Felder
338
Alex Booker

Dies ist eine neue Funktion in C # 6, die als Element mit Ausdruckskörper bezeichnet wird und mit der Sie eine Nur-Getter-Eigenschaft mithilfe einer Lambda-ähnlichen Funktion definieren können.

Während es für das Folgende als syntaktischer Zucker betrachtet wird, erzeugen sie möglicherweise nicht identische IL:

public int MaxHealth
{
    get
    {
        return Memory[Address].IsValid
               ?   Memory[Address].Read<int>(Offs.Life.MaxHp)
               :   0;
    }
}

Wenn Sie beide oben genannten Versionen kompilieren und die jeweils generierte IL vergleichen, werden Sie feststellen, dass sie [~ # ~] fast [~ # ~] sind gleich.

Hier ist die IL für die klassische Version in dieser Antwort, wenn sie in einer Klasse mit dem Namen TestClass definiert ist:

.property instance int32 MaxHealth()
{
    .get instance int32 TestClass::get_MaxHealth()
}

.method public hidebysig specialname 
    instance int32 get_MaxHealth () cil managed 
{
    // Method begins at RVA 0x2458
    // Code size 71 (0x47)
    .maxstack 2
    .locals init (
        [0] int32
    )

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
    IL_0007: ldarg.0
    IL_0008: ldfld int64 TestClass::Address
    IL_000d: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
    IL_0012: ldfld bool MemoryAddress::IsValid
    IL_0017: brtrue.s IL_001c

    IL_0019: ldc.i4.0
    IL_001a: br.s IL_0042

    IL_001c: ldarg.0
    IL_001d: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
    IL_0022: ldarg.0
    IL_0023: ldfld int64 TestClass::Address
    IL_0028: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
    IL_002d: ldarg.0
    IL_002e: ldfld class Offs TestClass::Offs
    IL_0033: ldfld class Life Offs::Life
    IL_0038: ldfld int64 Life::MaxHp
    IL_003d: callvirt instance !!0 MemoryAddress::Read<int32>(int64)

    IL_0042: stloc.0
    IL_0043: br.s IL_0045

    IL_0045: ldloc.0
    IL_0046: ret
} // end of method TestClass::get_MaxHealth

Und hier ist die IL für die Memberversion mit dem Ausdruck "body", wenn sie in einer Klasse mit dem Namen TestClass definiert ist:

.property instance int32 MaxHealth()
{
    .get instance int32 TestClass::get_MaxHealth()
}

.method public hidebysig specialname 
    instance int32 get_MaxHealth () cil managed 
{
    // Method begins at RVA 0x2458
    // Code size 66 (0x42)
    .maxstack 2

    IL_0000: ldarg.0
    IL_0001: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
    IL_0006: ldarg.0
    IL_0007: ldfld int64 TestClass::Address
    IL_000c: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
    IL_0011: ldfld bool MemoryAddress::IsValid
    IL_0016: brtrue.s IL_001b

    IL_0018: ldc.i4.0
    IL_0019: br.s IL_0041

    IL_001b: ldarg.0
    IL_001c: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress> TestClass::Memory
    IL_0021: ldarg.0
    IL_0022: ldfld int64 TestClass::Address
    IL_0027: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::get_Item(!0)
    IL_002c: ldarg.0
    IL_002d: ldfld class Offs TestClass::Offs
    IL_0032: ldfld class Life Offs::Life
    IL_0037: ldfld int64 Life::MaxHp
    IL_003c: callvirt instance !!0 MemoryAddress::Read<int32>(int64)

    IL_0041: ret
} // end of method TestClass::get_MaxHealth

Weitere Informationen zu dieser und anderen neuen Funktionen in C # 6 finden Sie unter https://msdn.Microsoft.com/en-us/magazine/dn802602.aspx .

Siehe diesen Beitrag nterschied zwischen Property und Field in C # 3.0 + zum Unterschied zwischen einem Field und einem Property Getter in C #.

Aktualisieren:

Beachten Sie, dass ausdrucksstarke Elemente um Eigenschaften, Konstruktoren, Finalizer und Indexer in C # 7.0 erweitert wurden.

32
Tyree Jackson

Ok ... Ich habe einen Kommentar abgegeben, dass sie unterschiedlich waren, aber ich konnte nicht genau erklären, wie, aber jetzt weiß ich es.

String Property { get; } = "value";

ist nicht dasselbe wie

String Property => "value";

Hier ist der Unterschied ...

Wenn Sie den automatischen Initialisierer verwenden, erstellt die Eigenschaft die Wertinstanz und verwendet diesen Wert dauerhaft. Im obigen Beitrag gibt es einen fehlerhaften Link zu Bill Wagner, der dies gut erklärt, und ich habe den richtigen Link gesucht, um ihn selbst zu verstehen.

In meiner Situation hat meine Eigenschaft einen Befehl in einem ViewModel für eine View automatisch initialisiert. Ich habe die Eigenschaft geändert, um Initialisierer mit Ausdruck zu verwenden, und der Befehl CanExecute funktioniert nicht mehr.

So sah es aus und so geschah es.

Command MyCommand { get; } = new Command();  //works

hier ist, was ich es geändert habe.

Command MyCommand => new Command();  //doesn't work properly

Der Unterschied besteht darin, dass ich mit { get; } = Den Befehl SAME in dieser Eigenschaft erstelle und darauf verweise. Wenn ich => Verwende, erstelle ich tatsächlich einen neuen Befehl und gebe ihn jedes Mal zurück, wenn die Eigenschaft aufgerufen wird. Daher konnte ich das CanExecute in meinem Befehl nie aktualisieren, da ich ihm immer sagte, dass er eine neue Referenz dieses Befehls aktualisieren soll.

{ get; } = // same reference
=>         // new reference

Alles in allem funktioniert es gut, wenn Sie nur auf ein Hintergrundfeld zeigen. Dies geschieht nur, wenn der Auto- oder Ausdruckskörper den Rückgabewert erstellt.

26

Es heißt Expression Bodied Member und wurde in C # 6 eingeführt. Es ist lediglich syntaktischer Zucker über einer get only-Eigenschaft.

Es ist äquivalent zu:

public int MaxHealth { get { return Memory[Address].IsValid ?
                             Memory[Address].Read<int>(Offs.Life.MaxHp) : 0; }

Ein Äquivalent einer Methodendeklaration ist verfügbar:

public string HelloWorld() => "Hello World";

Hauptsächlich ermöglicht es Ihnen, das Boilerplate zu verkürzen.

16
Yuval Itzchakov

Ein weiterer wichtiger Punkt, wenn Sie C # 6 verwenden:

'=>' kann anstelle von 'get' verwendet werden und ist only für 'get only' Methoden - it Kann nicht mit einem 'Set' verwendet werden.

Informationen zu C # 7 finden Sie im Kommentar von @avenmore weiter unten. Es kann jetzt an mehreren Stellen verwendet werden. Hier ist eine gute Referenz - https://csharp.christiannagel.com/2017/01/25/expressionbodiedmembers/

6
Chris Halcrow