Freigeben über


Musterübereinstimmung Span<char> auf eine konstante Zeichenkette

Anmerkung

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 sind in den einschlägigen Notizen zum Sprachdesign-Meeting (LDM).

Weitere Informationen über den Prozess zur Aufnahme von Feature Speclets in den C#-Sprachstandard finden Sie in dem Artikel über die Spezifikationen.

Zusammenfassung

Erlauben Sie den Mustervergleich einer Span<char> und eine ReadOnlySpan<char> auf eine konstante Zeichenfolge.

Motivation

Für die Leistung, die Verwendung von Span<char> und ReadOnlySpan<char> wird in vielen Szenarien gegenüber String bevorzugt. Das Framework hat viele neue APIs hinzugefügt, mit denen Sie ReadOnlySpan<char> anstelle einer stringverwenden können.

Ein gängiger Vorgang für Zeichenfolgen besteht darin, einen Switch zu verwenden, um zu testen, ob es sich um einen bestimmten Wert handelt, und der Compiler optimiert einen solchen Schalter. Allerdings gibt es derzeit keine Möglichkeit, dasselbe auf einer ReadOnlySpan<char> effizienter zu gestalten, als den Wechsel und die Optimierung manuell durchzuführen.

Zur Förderung der Einführung von ReadOnlySpan<char> erlauben wir einen Mustervergleich ReadOnlySpan<char>, mit einer Konstante string, und kann somit auch in einem Schalter verwendet werden.

static bool Is123(ReadOnlySpan<char> s)
{
    return s is "123";
}

static bool IsABC(Span<char> s)
{
    return s switch { "ABC" => true, _ => false };
}

Detailliertes Design

Wir ändern die -Spezifikation für Konstantenmuster wie folgt, wobei die vorgeschlagene Ergänzung fett hervorgehoben ist.

Angesichts eines Mustereingabewerts e und ein konstantes Muster P mit umgerechnetem Wert v,

  • wenn e einen Integral- oder Enum-Typ oder eine nullbare Form eines dieser Typen hat und v hat einen integralen Typ, das Muster Ppasst zu der Wert e wenn das Ergebnis des Ausdrucks e == v is true; ansonsten
  • Wenn e vom Typ System.Span<char> oder System.ReadOnlySpan<char>ist und c eine konstante Zeichenfolge ist und c keinen konstanten Wert von nullaufweist, wird das Muster als übereinstimmend betrachtet, wenn System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))truezurückgibt.
  • das Muster Ppasst zu der Wert e wenn object.Equals(e, v) gibt zurück true.

Bekannte Mitglieder

System.Span<T> und System.ReadOnlySpan<T> mit dem Namen übereinstimmen, müssen ref structs, und kann außerhalb von corlib definiert werden.

System.MemoryExtensions wird nach Namen abgeglichen und kann außerhalb von corlib definiert werden.

Die Unterschrift von System.MemoryExtensions.SequenceEqual Überlastungen müssen übereinstimmen:

  • public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)
  • public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)

Die Unterschrift von System.MemoryExtensions.AsSpan müssen übereinstimmen:

  • public static System.ReadOnlySpan<char> AsSpan(string)

Methoden mit optionalen Parametern werden von der Berücksichtigung ausgeschlossen.

Nachteile

Nichts

Alternativen

Nichts

Ungelöste Fragen

  1. Sollte die Übereinstimmung unabhängig von MemoryExtensions.SequenceEqual() usw.?

    ... wird das Muster als übereinstimmend angesehen, wenn e.Length == c.Length und e[i] == c[i] für alle Zeichen in e.

    Empfehlung: Definieren Sie im Sinne von MemoryExtensions.SequenceEqual() für Leistung. Wenn MemoryExtensions fehlt, melden Sie den Kompilierungsfehler.

  2. Sollte der Abgleich mit (string)null erlaubt sein?

    Wenn ja, sollte (string)null fassen "" seit MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")?

    static bool IsEmpty(ReadOnlySpan<char> span)
    {
        return span switch
        {
            (string)null => true, // ok?
            "" => true,           // error: unreachable?
            _ => false,
        };
    }
    

    Empfehlung: Konstantes Muster (string)null sollte als Fehler gemeldet werden.

  3. Sollte die Konstantenmusterübereinstimmung einen Laufzeittyptest des Ausdruckswerts für Span<char> oder ReadOnlySpan<char>?

    static bool Is123<T>(Span<T> s)
    {
        return s is "123"; // test for Span<char>?
    }
    
    static bool IsABC<T>(Span<T> s)
    {
        return s is Span<char> and "ABC"; // ok?
    }
    
    static bool IsEmptyString<T>(T t) where T : ref struct
    {
        return t is ""; // test for ReadOnlySpan<char>, Span<char>, string?
    }
    

    Empfehlung: Kein impliziter Laufzeittyptest für konstanten Muster. (IsABC<T>() Beispiel ist erlaubt, weil der Typentest explizit ist).

    Diese Empfehlung wurde nicht implementiert. Alle vorherigen Beispiele erzeugen einen Compilerfehler.

  4. Sollte die Subsumtion konstante Zeichenfolgenmuster, Listenmuster und Length Eigenschaftsmuster?

    static int ToNum(ReadOnlySpan<char> s)
    {
        return s switch
        {
            { Length: 0 } => 0,
            "" => 1,        // error: unreachable?
            ['A',..] => 2,
            "ABC" => 3,     // error: unreachable?
            _ => 4,
        };
    }
    

    Empfehlung: Gleiches Subsumtionsverhalten wie bei der Verwendung des Ausdruckswerts string. (Bedeutet das, dass keine Subsumtion zwischen konstanten Zeichenketten, Listenmustern und Length, andere als die Behandlung [..] als übereinstimmend mit jeder?)

Entwurfsbesprechungen

https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-07.md#readonlyspanchar-patterns