Condividi tramite


Corrispondenza del modello Span<char> in una stringa costante

Nota

Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.

Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note language design meeting (LDM) pertinenti.

Altre informazioni sul processo per l'adozione dei speclet delle funzionalità nello standard del linguaggio C# sono disponibili nell'articolo relativo alle specifiche .

Sommario

Consenti la corrispondenza di pattern tra Span<char> e ReadOnlySpan<char> su una stringa costante.

Motivazione

Per la performance, l'utilizzo di Span<char> e ReadOnlySpan<char> è preferibile rispetto alle stringhe in molti scenari. Il framework ha aggiunto molte nuove API per consentire di usare ReadOnlySpan<char> al posto di un string.

Un'operazione comune sulle stringhe consiste nell'usare un'opzione per verificare se si tratta di un valore specifico e il compilatore ottimizza tale opzione. Tuttavia, attualmente non è possibile eseguire la stessa operazione su un ReadOnlySpan<char> in modo efficiente, ad eccezione dell'implementazione del commutatore e dell'ottimizzazione manualmente.

Per incoraggiare l'adozione di ReadOnlySpan<char> è possibile che i criteri corrispondano a un ReadOnlySpan<char>, in una costante string, consentendo così l'uso in un commutatore.

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

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

Progettazione dettagliata

La specifica di per i modelli costanti viene modificata nel modo seguente (l'aggiunta proposta è illustrata in grassetto):

Dato un valore di input del pattern e e un pattern costante P con valore convertito v,

  • se e ha un tipo integrale o un tipo enumerazione oppure una forma nullable di uno di questi e v ha un tipo integrale, il criterio Pcorrisponde il valore e se il risultato dell'espressione e == v è true; altrimenti
  • Se e è di tipo System.Span<char> o System.ReadOnlySpan<char>e c è una stringa costante e c non ha un valore costante di null, il criterio viene considerato corrispondente se System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c)) restituisce true.
  • il criterio Pcorrisponde il valore e se object.Equals(e, v) restituisce true.

Membri noti

System.Span<T> e System.ReadOnlySpan<T> corrispondono in base al nome, devono essere di tipo ref structe possono essere definiti all'esterno di corlib.

System.MemoryExtensions corrisponde al nome e può essere definito all'esterno di corlib.

La firma degli overload di System.MemoryExtensions.SequenceEqual deve corrispondere:

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

La firma di System.MemoryExtensions.AsSpan deve corrispondere a:

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

I metodi con parametri facoltativi vengono esclusi dalla considerazione.

Svantaggi

Nessuno

Alternative

Nessuno

Domande non risolte

  1. La corrispondenza deve essere definita in modo indipendente da MemoryExtensions.SequenceEqual() e così via?

    ... il pattern viene considerato corrispondente se e.Length == c.Length e e[i] == c[i] corrispondono per tutti i caratteri in e.

    Raccomandazione: definire in termini di MemoryExtensions.SequenceEqual() per le prestazioni. Se MemoryExtensions manca, segnalare l'errore di compilazione.

  2. Deve essere consentito il confronto con (string)null?

    In tal caso, (string)null dovrebbe sottosumere "" poiché MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan("")?

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

    raccomandazione: il modello costante (string)null deve essere segnalato come errore.

  3. La corrispondenza con il pattern costante deve includere un test del tipo di runtime del valore dell'espressione su Span<char> o 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?
    }
    

    Raccomandazione: nessun test implicito del tipo di runtime per il modello costante. (IsABC<T>() esempio è consentito perché il test del tipo è esplicito.

    Questa raccomandazione non è stata implementata. Tutti gli esempi precedenti generano un errore del compilatore.

  4. La subsommazione deve considerare modelli di stringa costanti, modelli di elenco e modelli di proprietà di Length?

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

    Raccomandazione: lo stesso comportamento di sottosumpazione usato quando il valore dell'espressione è string. (Ciò significa che non esiste alcuna inclusione tra stringhe costanti, modelli di elenco e Length, tranne nel caso in cui [..] sia considerato corrispondente a qualsiasi?)

Riunioni di progettazione

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