Freigeben über


Unformatiertes Zeichenfolgenliteral

Hinweis

Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.

Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den relevanten Sprachentwurfsbesprechungen (LDM)-Notizen erfasst.

Weitere Informationen zum Einführen von Featurespezifikationen in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.

Champion Issue: https://github.com/dotnet/csharplang/issues/8647

Zusammenfassung

Lassen Sie eine neue Form des Zeichenfolgenliterals zu, die mit mindestens drei """ Zeichen beginnt (aber kein Maximum), optional gefolgt von einem new_line, dem Inhalt der Zeichenfolge und endet dann mit der gleichen Anzahl von Anführungszeichen, mit denen das Literal begonnen hat. Beispiel:

var xml = """
          <element attr="content"/>
          """;

Da der geschachtelte Inhalt möglicherweise selbst verwendet """ werden soll, können die Anfangs-/Endtrennzeichen wie folgt aussehen:

var xml = """"
          Ok to use """ here
          """";

Damit der Text leicht zu lesen ist und den Einzug ermöglicht, den Entwickler wie im Code verwenden, werden diese Zeichenfolgenliterale bei der Erstellung des endgültigen Literalwerts natürlich den in der letzten Zeile angegebenen Einzug entfernen. Beispiel: ein Literal des Formulars:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

Hat den Inhalt:

<element attr="content">
  <body>
  </body>
</element>

Auf diese Weise kann Code natürlich aussehen, während weiterhin Literale erzeugt werden, die erwünscht sind, und Laufzeitkosten vermieden werden, wenn dies die Verwendung spezieller Zeichenfolgenmanipulationsroutinen erfordert.

Wenn das Einzugsverhalten nicht gewünscht wird, ist es auch trivial, wie folgt zu deaktivieren:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

Ein einzelnes Linienformular wird ebenfalls unterstützt. Sie beginnt mit mindestens drei """ Zeichen (aber nicht maximal), dem Inhalt der Zeichenfolge (die keine new_line Zeichen enthalten kann), und endet dann mit derselben Anzahl von Anführungszeichen, mit denen das Literal begonnen hat. Beispiel:

var xml = """<summary><element attr="content"/></summary>""";

Interpolierte unformatierte Zeichenfolgen werden ebenfalls unterstützt. In diesem Fall gibt die Zeichenfolge die Anzahl der geschweiften Klammern an, die zum Starten einer Interpolation erforderlich sind (bestimmt durch die Anzahl der Dollarzeichen, die am Anfang des Literals vorhanden sind). Jede geschweifte Sequenz mit weniger geschweiften Klammern als inhalt behandelt wird. Beispiel:

var json = $$"""
             {
                "summary": "text",
                "length" : {{value.Length}},
             };
             """;

Motivation

C# bietet keine allgemeine Möglichkeit, einfache Zeichenfolgenliterale zu erstellen, die effektiv beliebiger Text enthalten können. Alle C#-Zeichenfolgenliteralformen benötigen heute eine Form der Escapeform, falls der Inhalt ein Sonderzeichen verwendet (immer, wenn ein Trennzeichen verwendet wird). Dies verhindert, dass Literale, die andere Sprachen enthalten, problemlos vorhanden sind (z. B. ein XML-, HTML- oder JSON-Literal).

Alle aktuellen Ansätze zur Form dieser Literale in C# erzwingen heute immer, dass der Benutzer den Inhalt manuell escapet. Die Bearbeitung an diesem Punkt kann sehr lästig sein, da die Flucht nicht vermieden werden kann und jedes Mal bearbeitet werden muss, wenn es in den Inhalten auftritt. Dies ist besonders schmerzhaft für Regexes, insbesondere wenn sie Anführungszeichen oder umgekehrte Schrägstriche enthalten. Selbst bei einer Zeichenfolge (@"") müssen Anführungszeichen selbst zu einer Mischung aus C# und regex interspersiert werden. { und } sind ähnlich frustrierend in interpolierten ($"") Zeichenfolgen.

Der Crux des Problems besteht darin, dass alle unsere Zeichenfolgen über ein festes Start-/End-Trennzeichen verfügen. Solange dies der Fall ist, müssen wir immer über einen Escapemechanismus verfügen, da der Zeichenfolgeninhalt möglicherweise dieses Endtrennzeichen in ihrem Inhalt angeben muss. Dies ist besonders problematisch, da dieses Trennzeichen " in vielen Sprachen sehr häufig verwendet wird.

Um dies zu beheben, ermöglicht dieser Vorschlag flexible Start- und Endtrennzeichen, sodass sie immer auf eine Weise vorgenommen werden können, die nicht mit dem Inhalt der Zeichenfolge in Konflikt stehen wird.

Ziele

  1. Stellen Sie einen Mechanismus bereit, mit dem alle Zeichenfolgenwerte vom Benutzer bereitgestellt werden können, ohne dass Escapesequenzen erforderlich sind. Da alle Zeichenfolgen ohne Escapesequenzen dargestellt werden müssen, muss es dem Benutzer immer möglich sein, Trennzeichen anzugeben, die garantiert nicht mit Textinhalten kollidieren.
  2. Unterstützen Sie Interpolationen auf die gleiche Weise. Da alle Zeichenfolgen ohne Escapezeichen dargestellt werden müssen, muss es dem Benutzer immer möglich sein, ein interpolation Trennzeichen anzugeben, das garantiert nicht mit Textinhalten kollidiert. Wichtig ist, dass Sprachen, die unsere Interpolationstrennzeichen ({ und }) verwenden, erstklassige und nicht schmerzhafte Verwendung fühlen.
  3. Mehrzeilen-Zeichenfolgenliterale sollten im Code angenehm aussehen und sollten keinen Einzug innerhalb der Kompilierungseinheit seltsam aussehen. Wichtig ist, dass Literalwerte, die selbst keinen Einzug haben, nicht gezwungen werden, die erste Spalte der Datei zu belegen, da dies den Codefluss aufbrechen kann und mit dem rest des Codes, der ihn umgibt, unausrichtungslos aussieht.
    • Dieses Verhalten sollte leicht überschreiben, während Literale klar und einfach zu lesen bleiben.
  4. Für alle Zeichenfolgen, die nicht selbst ein new_line Anführungszeichen enthalten oder mit einem Anführungszeichen (") enden, sollte es möglich sein, das Zeichenfolgenliteral selbst in einer einzelnen Zeile darzustellen.
    • Optional könnten wir dies mit zusätzlicher Komplexität verfeinern, um anzugeben, dass: Für alle Zeichenfolgen, die nicht selbst ein new_line (aber mit einem Anführungszeichen " beginnen oder enden können), sollte es möglich sein, das Zeichenfolgenliteral selbst in einer einzelnen Zeile darzustellen. Weitere Informationen finden Sie im erweiterten Vorschlag im Drawbacks Abschnitt.

Detailliertes Design (Nicht-Interpolationsfall)

Wir fügen eine neue string_literal Produktion mit der folgenden Form hinzu:

string_literal
    : regular_string_literal
    | verbatim_string_literal
    | raw_string_literal
    ;

raw_string_literal
    : single_line_raw_string_literal
    | multi_line_raw_string_literal
    ;

raw_string_literal_delimiter
    : """
    | """"
    | """""
    | etc.
    ;

raw_content
    : not_new_line+
    ;

single_line_raw_string_literal
    : raw_string_literal_delimiter raw_content raw_string_literal_delimiter
    ;

multi_line_raw_string_literal
    : raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

not_new_line
    : <any unicode character that is not new_line>
    ;

Das endende Trennzeichen an ein raw_string_literal muss mit dem Starttrennzeichen übereinstimmen. Wenn das Starttrennzeichen also das endende Trennzeichen ist """"" , muss auch das sein.

Die oben genannte Grammatik für eine raw_string_literal sollte interpretiert werden als:

  1. Sie beginnt mit mindestens drei Anführungszeichen (aber keine Obergrenze für Anführungszeichen).
  2. Anschließend wird der Inhalt in derselben Zeile wie die Anfangszeichen fortgesetzt. Diese Inhalte in derselben Zeile können leer oder nicht leer sein. "blank" ist synonym für "ganze Leerzeichen".
  3. Wenn der Inhalt in derselben Zeile nicht leer ist, können keine weiteren Inhalte folgen. Mit anderen Worten, das Literal muss mit derselben Anzahl von Anführungszeichen in derselben Zeile enden.
  4. Wenn der Inhalt in derselben Zeile leer ist, kann das Literal mit einer new_line und mehreren nachfolgenden Inhaltszeilen und new_line-n fortfahren.
    • Eine Inhaltszeile ist ein beliebiger Text mit Ausnahme eines new_line.
    • Es endet dann mit einer new_line Zahl (möglicherweise Null) von whitespace und derselben Anzahl von Anführungszeichen, mit denen das Literal begonnen hat.

Unformatierter Zeichenfolgenliteralwert

Die Teile zwischen Dem Anfang und Ende raw_string_literal_delimiter werden verwendet, um den Wert der raw_string_literal folgenden Art zu bilden:

  • Im Fall des Werts single_line_raw_string_literal des Literals ist genau der Inhalt zwischen dem Anfang und dem Ende raw_string_literal_delimiter.
  • Im Falle der initialen multi_line_raw_string_literalwhitespace* new_line und letzten ist nicht new_line whitespace* Teil des Werts der Zeichenfolge. Der letzte whitespace* Teil vor dem raw_string_literal_delimiter Terminal wird jedoch als "Einzugs-Leerzeichen" betrachtet und wirkt sich darauf aus, wie die anderen Linien interpretiert werden.
  • Um den endgültigen Wert abzurufen, wird die Sequenz (raw_content | new_line)* der Exemplare ausgeführt, und es wird Folgendes ausgeführt:
    • Wenn der new_line Inhalt des Inhalts new_line dem endgültigen Zeichenfolgenwert hinzugefügt wird.
    • Wenn es sich nicht um ein Leerzeichen handelt raw_content (d. h. not_new_line+ enthält ein Nicht-Zeichenwhitespace ):
      • Das Leerzeichen "Einzug" muss ein Präfix des raw_content. Andernfalls ist dies ein Fehler.
      • Das Leerzeichen "Einzug" wird vom Anfang raw_content entfernt, und der Rest wird dem endgültigen Zeichenfolgenwert hinzugefügt.
    • Wenn es sich um ein Leerzeichen handelt raw_content (d. h. not_new_line+ vollständig whitespace):
      • Das Leerzeichen "Einzug" muss ein Präfix des raw_content Oder das raw_content Präfix des Leerzeichens "Einzug" sein. Andernfalls ist dies ein Fehler.
      • da ein Großteil des Leerzeichens "Einzug" vom Anfang raw_content entfernt wird und jeder Rest dem endgültigen Zeichenfolgenwert hinzugefügt wird.

Klarstellungen:

  1. A single_line_raw_string_literal ist nicht in der Lage, eine Zeichenfolge mit einem new_line Wert darin darzustellen. A single_line_raw_string_literal nimmt nicht am Kürzen des Leerzeichens "Einzug" teil. Der Wert ist immer die genauen Zeichen zwischen dem Anfangs- und dem Endtrennzeichen.

  2. Da ein multi_line_raw_string_literal Ende new_line der letzten Inhaltszeile ignoriert wird, stellt die folgende Zeichenfolge eine Zeichenfolge ohne Anfang new_line und ohne Beendigung dar. new_line

var v1 = """
         This is the entire content of the string.
         """;

Dies behält die Symmetrie bei, wie der Start new_line ignoriert wird, und bietet auch eine einheitliche Möglichkeit, um sicherzustellen, dass der "Einzugs-Leerraum" immer angepasst werden kann. Um eine Zeichenfolge mit einem Terminal new_line darzustellen, muss eine zusätzliche Zeile wie folgt angegeben werden:

var v1 = """
         This string ends with a new line.

         """;
  1. A single_line_raw_string_literal cannot represent a string value that starts or ends with a quote (") though an augmentation to this proposal is provided in the Drawbacks section that shows how that could be supported.

  2. A multi_line_raw_string_literal beginnt mit whitespace* new_line dem Folgen der ersten raw_string_literal_delimiter. Dieser Inhalt nach dem Trennzeichen wird vollständig ignoriert und wird beim Bestimmen des Werts der Zeichenfolge nicht verwendet. Auf diese Weise kann ein Mechanismus angegeben raw_string_literal werden, dessen Inhalt mit einem " Zeichen selbst beginnt. Beispiel:

var v1 = """
         "The content of this string starts with a quote
         """;
  1. Eine raw_string_literal kann auch Inhalte darstellen, die mit einem Anführungszeichen (") enden. Dies wird unterstützt, da sich das Trennzeichen für das Beenden in einer eigenen Zeile befindet. Beispiel:
var v1 = """
         "The content of this string starts and ends with a quote"
         """;
var v1 = """
         ""The content of this string starts and ends with two quotes""
         """;
  1. Die Anforderung, dass ein "Leerzeichen" raw_content entweder ein Präfix des Leerzeichens oder des Leerzeichens "Einzug" sein muss, muss ein Präfix dafür sein, dass verwirrende Szenarien mit gemischten Leerzeichen nicht auftreten, insbesondere, da es unklar wäre, was mit dieser Zeile geschehen sollte. Der folgende Fall ist beispielsweise illegal:
var v1 = """
         Start
<tab>
         End
         """;
  1. Hier ist das Leerzeichen "Einzug" neun Leerzeichen, aber das Leerzeichen raw_content beginnt nicht mit einem Präfix davon. Es gibt keine klare Antwort darauf, wie diese <tab> Zeile überhaupt behandelt werden soll. Sollte sie ignoriert werden? Sollte es gleich sein wie .........<tab>? Als solche scheint es illegal zu machen, um Verwirrung zu vermeiden.

  2. Die folgenden Fälle sind jedoch legal und stellen dieselbe Zeichenfolge dar:

var v1 = """
         Start
<four spaces>
         End
         """;
var v1 = """
         Start
<nine spaces>
         End
         """;

In beiden Fällen ist das Leerzeichen "Einzug" neun Leerzeichen. Und in beiden Fällen entfernen wir so viel von diesem Präfix wie möglich, was dazu führt, dass das Leerzeichen raw_content in jedem Fall leer ist (nicht zählen alle new_line). Auf diese Weise können Benutzer diese Zeilen nicht sehen und möglicherweise nicht mehr über Leerzeichen in diesen Zeilen suchen, wenn sie diese Zeilen kopieren/einfügen oder bearbeiten.

  1. Im Fall von:
var v1 = """
         Start
<ten spaces>
         End
         """;

Der Einzugs-Leerraum ist immer noch neun Leerzeichen. Hier werden wir jedoch so viel wie möglich vom "Einzugs-Leerzeichen" entfernen, und das "Leere" raw_content trägt zu einem einzigen Leerzeichen zum endgültigen Inhalt bei. Dies ermöglicht Fälle, in denen der Inhalt Leerzeichen in diesen Zeilen benötigt, die beibehalten werden sollen.

  1. Das folgende ist technisch nicht legal:
var v1 = """
         """;

Dies liegt daran, dass der Anfang der unformatierten Zeichenfolge eine new_line (was sie tut) haben muss, aber das Ende muss auch eine new_line (was nicht der Fall ist). Die minimalen gesetzlichen Bestimmungen raw_string_literal sind:

var v1 = """

         """;

Diese Zeichenfolge ist jedoch entschieden uninteressant, da sie gleichbedeutend ""ist.

Einzugsbeispiele

Der "Einzugs-Leerraum"-Algorithmus kann auf mehreren Eingaben dargestellt werden, z. B. In den folgenden Beispielen wird das vertikale Balkenzeichen | verwendet, um die erste Spalte in der resultierenden unformatierten Zeichenfolge zu veranschaulichen:

Beispiel 1 – Standardfall

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

wird interpretiert als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |</element>
           """;

Beispiel 2 – Endtrennzeichen in derselben Zeile wie Der Inhalt.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>""";

Dies ist illegal. Die letzte Inhaltszeile muss mit einer new_line.

Beispiel 3 – Endtrennzeichen vor dem Starttrennzeichen

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

wird interpretiert als

var xml = """
|          <element attr="content">
|            <body>
|            </body>
|          </element>
""";

Beispiel 4 – Endtrennzeichen nach dem Starttrennzeichen

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
              """;

Dies ist illegal. Die Inhaltszeilen müssen mit dem Leerzeichen "Einzug" beginnen.

Beispiel 5 – Leere Zeile

var xml = """
          <element attr="content">
            <body>
            </body>

          </element>
          """;

wird interpretiert als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Beispiel 6 – Leere Linie mit weniger Leerzeichen als Präfix (Punkte stellen Leerzeichen dar)

var xml = """
          <element attr="content">
            <body>
            </body>
....
          </element>
          """;

wird interpretiert als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Beispiel 7 – Leere Zeile mit mehr Leerzeichen als Präfix (Punkte stellen Leerzeichen dar)

var xml = """
          <element attr="content">
            <body>
            </body>
..............
          </element>
          """;

wird interpretiert als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |....
          |</element>
           """;

Detailliertes Design (Interpolationsfall)

Interpolationen in normalen interpolierten Zeichenfolgen (z. B. $"...") werden heute durch die Verwendung des { Zeichens unterstützt, um eine interpolation Escapesequenz zu starten und {{ ein tatsächliches offenes geschweiftes Klammerzeichen einzufügen. Die Verwendung dieses Mechanismus würde gegen die Ziele "1" und "2" dieses Vorschlags verstoßen. Sprachen, die { als Kernzeichen (Beispiele für JavaScript, JSON, Regex und sogar eingebettetes C#) verfügen, benötigen jetzt das Escapen und Rückgängigmachen des Zwecks von unformatierten Zeichenfolgenliteralen.

Zur Unterstützung von Interpolationen stellen wir sie anders vor als normale $" interpolierte Zeichenfolgen. Insbesondere beginnt ein interpolated_raw_string_literal Zeichen mit einer bestimmten Anzahl von $ Zeichen. Die Anzahl dieser Zeichen gibt an, wie viele { (und }) Zeichen im Inhalt des Literals benötigt werden, um die interpolationTrennzeichen zu trennen. Wichtig ist, dass es weiterhin keinen Fluchtmechanismus für geschweifte Klammern gibt. Genau wie bei Anführungszeichen (") kann das Literal selbst immer sicherstellen, dass es Trennzeichen für die Interpolationen angibt, die sicher sind, dass sie nicht mit einem der restlichen Inhalte der Zeichenfolge kollidieren. Beispielsweise kann ein JSON-Literal mit Interpolationslöchern wie folgt geschrieben werden:

var v1 = $$"""
         {
            "orders": 
            [
                { "number": {{order_number}} }
            ]
         }
         """

Hier entspricht die {{...}} erforderliche Anzahl von zwei geschweiften Klammern, die durch das $$ Trennzeichenpräfix angegeben sind. Bei einem einzelnen $ bedeutet dies, dass die Interpolation genauso wie {...} in normalen interpolierten Zeichenfolgenliteralen angegeben wird. Dies bedeutet, dass ein interpoliertes Literal mit N$ Zeichen eine Abfolge von 2*N-1 geschweiften Klammern (desselben Typs in einer Zeile) aufweisen kann. Die letzten N geschweiften Klammern beginnen (oder enden) eine Interpolation, und die verbleibenden N-1 geschweiften Klammern sind nur Inhalt. Beispiel:

var v1 = $$"""X{{{1+1}}}Z""";

In diesem Fall gehören die inneren beiden {{ und }} geschweiften Klammern zur Interpolation, und die äußeren Singularklammern sind nur Inhalt. Die obige Zeichenfolge entspricht also dem Inhalt X{2}Z. Das Vorhandensein 2*N (oder mehr) geschweifte Klammern ist immer ein Fehler. Um längere Klammernreihen als Inhalt zu haben, muss die Anzahl der $ Zeichen entsprechend erhöht werden.

Interpolierte unformatierte Zeichenfolgenliterale werden wie folgt definiert:

interpolated_raw_string_literal
    : single_line_interpolated_raw_string_literal
    | multi_line_interpolated_raw_string_literal
    ;

interpolated_raw_string_start
    : $
    | $$
    | $$$
    | etc.
    ;

interpolated_raw_string_literal_delimiter
    : interpolated_raw_string_start raw_string_literal_delimiter
    ;

single_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter
    ;

multi_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

interpolated_raw_content
    : (not_new_line | raw_interpolation)+
    ;

raw_interpolation
    : raw_interpolation_start interpolation raw_interpolation_end
    ;

raw_interpolation_start
    : {
    | {{
    | {{{
    | etc.
    ;

raw_interpolation_end
    : }
    | }}
    | }}}
    | etc.
    ;

Das oben genannte ist mit der Definition von raw_string_literal , aber mit einigen wichtigen Unterschieden vergleichbar. A interpolated_raw_string_literal sollte folgendermaßen interpretiert werden:

  1. Sie beginnt mit mindestens einem Dollarzeichen (aber keine Obergrenze) und dann drei Anführungszeichen (auch ohne Obergrenze).
  2. Anschließend wird der Inhalt in derselben Zeile wie die Anfangsvorführungszeichen fortgesetzt. Dieser Inhalt in derselben Zeile kann leer oder nicht leer sein. "blank" ist synonym für "ganze Leerzeichen".
  3. Wenn der Inhalt in derselben Zeile nicht leer ist, können keine weiteren Inhalte folgen. Mit anderen Worten, das Literal muss mit derselben Anzahl von Anführungszeichen in derselben Zeile enden.
  4. Wenn der Inhalt in derselben Zeile leer ist, kann das Literal mit einer new_line und mehreren nachfolgenden Inhaltszeilen und new_line-n fortfahren.
    • Eine Inhaltszeile ist ein beliebiger Text mit Ausnahme eines new_line.
    • Eine Inhaltszeile kann an einer beliebigen Position mehrere raw_interpolation Vorkommen enthalten. Der raw_interpolation Wert muss mit einer gleichen Anzahl offener geschweifter Klammern ({) beginnen wie die Anzahl der Dollarzeichen am Anfang des Literals.
    • Wenn "Einzugs-Leerzeichen" nicht leer ist, kann eine raw_interpolation nicht sofort einem new_line.
    • Die raw_interpolation regeln nach §12.8.3. Alle raw_interpolation müssen mit derselben Anzahl geschlossener Klammern (}) enden wie Dollarzeichen und geöffnete Klammern.
    • Jede interpolation Kann selbst neue Zeilen auf die gleiche Weise enthalten wie eine interpolation in einer normalen verbatim_string_literal (@"").
    • Es endet dann mit einer new_line Zahl (möglicherweise Null) von whitespace und derselben Anzahl von Anführungszeichen, mit denen das Literal begonnen hat.

Die Berechnung des interpolierten Zeichenfolgenwerts folgt den gleichen Regeln wie ein Normalwert raw_string_literal , mit Ausnahme der Aktualisierung, um Zeilen zu behandeln, die s enthalten raw_interpolation. Das Erstellen des Zeichenfolgenwerts erfolgt auf die gleiche Weise, nur wenn die Interpolationslöcher durch die Werte ersetzt werden, die diese Ausdrücke zur Laufzeit erzeugen. Wenn die interpolated_raw_string_literal Werte der Interpolationen in eine FormattableString konvertiert werden, werden die Werte der Interpolationen in ihrer jeweiligen Reihenfolge an das arguments Array übergeben.FormattableString.Create Der Rest des Inhalts des Inhalts nach interpolated_raw_string_literaldem Entfernen des Einzugs von allen Zeilen wird verwendet, um die format an die Zeichenfolge übergebene FormattableString.CreateZeichenfolge zu generieren, mit Ausnahme der entsprechenden nummerierten {N} Inhalte an jeder Stelle, an der ein raw_interpolation Einzug stattgefunden hat (oder {N,constant} in dem Fall, wenn es interpolation sich um das Formular expression ',' constant_expressionhandelt).

Es gibt eine Mehrdeutigkeit in der obigen Spezifikation. Insbesondere, wenn ein Abschnitt in { Text und { einer Interpolation abut. Beispiel:

var v1 = $$"""
         {{{order_number}}}
         """

Dies kann wie folgt interpretiert werden: {{ {order_number } }} oder { {{order_number}} }. Da der frühere Ausdruck jedoch illegal ist (kein C#-Ausdruck könnte mit {) beginnen, wäre es sinnlos, auf diese Weise zu interpretieren. Daher interpretieren wir in letzterer Weise, wo die innersten und { geschweiften } Klammern die Interpolation bilden, und alle äußersten formen den Text. In Zukunft kann dies ein Problem sein, wenn die Sprache jemals Ausdrücke unterstützt, die von geschweiften Klammern umgeben sind. In diesem Fall empfiehlt es sich jedoch, einen solchen Fall wie folgt zu schreiben: {{({some_new_expression_form})}}. Hier würden Klammern dazu beitragen, den Ausdrucksteil aus dem rest der Literal-/Interpolation zu bestimmen. Dies hat bereits Vorrang damit, wie ternäre bedingte Ausdrücke umschlossen werden müssen, um nicht mit dem Formatierungs-/Ausrichtungsbezeichner einer Interpolation (z. B. {(x ? y : z)}) in Konflikt zu stehen.

Nachteile

Unformatierte Zeichenfolgenliterale fügen der Sprache mehr Komplexität hinzu. Wir haben bereits viele Zeichenfolgenliteralformen für zahlreiche Zwecke. "" Zeichenfolgen, @"" Zeichenfolgen und $"" Zeichenfolgen verfügen bereits über viel Leistungsfähigkeit und Flexibilität. Aber sie alle haben keine Möglichkeit, rohe Inhalte bereitzustellen, die nie entweichen müssen.

Die oben genannten Regeln unterstützen den Fall von 4.a nicht:

  1. ...
    • Optional könnten wir dies mit zusätzlicher Komplexität verfeinern, um anzugeben, dass: Für alle Zeichenfolgen, die nicht selbst ein new_line (aber mit einem Anführungszeichen " beginnen oder enden können), sollte es möglich sein, das Zeichenfolgenliteral selbst in einer einzelnen Zeile darzustellen.

Das liegt daran, dass wir nicht wissen müssen, dass ein Anfangs- oder Endzitat (") zum Inhalt und nicht zum Trennzeichen selbst gehören sollte. Wenn dies jedoch ein wichtiges Szenario ist, das wir unterstützen möchten, können wir ein paralleles ''' Konstrukt hinzufügen, das mit dem """ Formular zusammengeht. Mit diesem parallelen Konstrukt kann eine einzelne Zeilenzeichenfolge, die beginnt und endet " , problemlos zusammen '''"This string starts and ends with quotes"''' mit dem parallelen Konstrukt """'This string starts and ends with apostrophes'"""geschrieben werden. Dies kann auch wünschenswert sein, um die visuelle Trennung von Anführungszeichen zu unterstützen, was bei der Einbettung von Sprachen hilfreich sein kann, die in erster Linie ein Anführungszeichen viel mehr als dann andere verwenden.

Alternativen

https://github.com/dotnet/csharplang/discussions/89 deckt hier viele Optionen ab. Alternativen sind zahlreiche, aber ich fühle mich zu weit in Komplexität und schlechte Ergonomie. Dieser Ansatz entscheidet sich für die Einfachheit, wenn Sie die Länge des Anfangs-/Ende-Anführungszeichens nur erhöhen, bis es keine Sorge um einen Konflikt mit dem Zeichenfolgeninhalt gibt. Es ermöglicht auch den Code, den Sie schreiben, gut eingerückt zu aussehen, während dennoch ein heruntergezogenes Literal erzeugt wird, das den meisten Code wünscht.

Eine der interessantesten potenziellen Variationen ist jedoch die Verwendung von ` (oder ```) Zaunen für diese unformatierten Zeichenfolgenliterale. Dies hätte mehrere Vorteile:

  1. Es würde vermeiden, dass alle Probleme mit Zeichenfolgen auftreten, die mit Anführungszeichen enden.
  2. Es würde vertraut aussehen, um Markdown zu markieren. Obwohl dies für sich selbst möglicherweise nicht gut ist, da Benutzer eine Markdown-Interpretation erwarten könnten.
  3. Ein unformatiertes Zeichenfolgenliteral müsste in den meisten Fällen nur mit einem einzelnen Zeichen beginnen und enden und würde nur mehrere in dem viel selteneren Fall von Inhalten benötigen, die back-ticks selbst enthalten.
  4. Es wäre natürlich, dies in Zukunft mit ```xmlmarkdown zu erweitern. Das gilt aber natürlich auch für die """ Form.

Insgesamt scheint der Nettovorteil hier jedoch klein zu sein. Im Einklang mit der C#-Geschichte sollte ich meiner Meinung nach " weiterhin das string literal Trennzeichen sein, genau wie für @"" und $"".

Planungsbesprechungen

Offene Probleme zur Diskussion Behobene Probleme:

  • [x] sollte ein einzelnes Linienformular vorliegen? Wir könnten es technisch nicht tun. Es würde jedoch bedeuten, dass einfache Zeichenfolgen, die keine Neueinline enthalten, immer mindestens drei Zeilen in Anspruch nehmen würden. Ich denke, wir sollten es sehr schwergewichtig sein, einzelne Linienkonstrukte zu erzwingen, um nur drei Linien zu sein, um es zu vermeiden.

Designentscheidung: Ja, wir haben eine einzige Linienform.

  • [x] sollten wir verlangen, dass eine mehrlineige Zeile mit einer Neueninline beginnen muss ? Ich denke, wir sollten. Es gibt uns auch die Möglichkeit, Dinge wie """xml in der Zukunft zu unterstützen.

Designentscheidung: Ja, wir werden verlangen, dass mehrereLine mit einer Neulinie beginnen müssen

  • [x] sollte die automatische Einrückung überhaupt erfolgen? Ich denke, wir sollten. Es macht Code so viel angenehmer aus.

Entwurfsentscheidung: Ja, automatisches Herunterstufen erfolgt.

  • [x] sollten wir gemeinsame Leerzeichen daran hindern, Leerzeichen zu mischen? Ich denke nicht, wir sollten. Tatsächlich gibt es eine gemeinsame Einzugsstrategie namens "Tabstopp für Einzug, Raum für Ausrichtung". Es wäre sehr natürlich, dies zu verwenden, um das Endtrennzeichen mit dem Starttrennzeichen in einem Fall auszurichten, in dem das Starttrennzeichen nicht auf einem Tabstopp beginnt.

Designentscheidung: Wir werden keine Einschränkungen beim Mischen von Leerzeichen haben.

  • [x] sollten wir etwas anderes für die Zäune verwenden? ` würde die Markdownsyntax entsprechen und bedeutete, dass wir diese Zeichenfolgen nicht immer mit drei Anführungszeichen beginnen müssen. Nur eine würde für den gemeinsamen Fall ausreichen.

Designentscheidung: Wir verwenden """

  • [x] sollten wir eine Anforderung haben, dass das Trennzeichen mehr Anführungszeichen als die längste Sequenz von Anführungszeichen im Zeichenfolgenwert aufweist? Technisch ist es nicht erforderlich. Zum Beispiel:
var v = """
        contents"""""
        """

Dies ist eine Zeichenfolge mit """ dem Trennzeichen. Mehrere Communitymitglieder haben angegeben, dass dies verwirrend ist, und wir sollten in einem Fall wie diesem erfordern, dass das Trennzeichen immer mehr Zeichen hat. Das wäre dann:

var v = """"""
        contents"""""
        """"""

Entwurfsentscheidung: Ja, das Trennzeichen muss länger sein als jede Sequenz von Anführungszeichen in der Zeichenfolge selbst.