Il String.Contains metodo assomiglia a questo internamentePerché String.Contain non chiama direttamente l'overload finale?
public bool Contains(string value)
{
return this.IndexOf(value, StringComparison.Ordinal) >= 0;
}
Il IndexOf
di sovraccarico che si chiama aspetto come questo
public int IndexOf(string value, StringComparison comparisonType)
{
return this.IndexOf(value, 0, this.Length, comparisonType);
}
Ecco un'altra chiamata è fatto per il sovraccarico di finale, che poi chiama il metodo in questione CompareInfo.IndexOf
, con la firma
public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
Pertanto, chiamando il il sovraccarico finale sarebbe il più veloce (sebbene possa essere considerato un micro-ottimizzazione nella maggior parte dei casi).
È possibile che manchi qualcosa di ovvio, ma perché il metodo Contains
non chiama il sovraccarico finale considerando direttamente che nessun altro lavoro è svolto nella chiamata intermedia e che le stesse informazioni sono disponibili in entrambe le fasi?
L'unico vantaggio è che se la firma del sovraccarico finale cambia, è necessario effettuare una sola modifica (quella del metodo intermedio) oppure esiste più rispetto alla progettazione?
Edit dai commenti (vedere Update 2 per la differenza di velocità spiegazione)
Per chiarire le differenze di prestazioni che sto ricevendo nel caso in cui ho fatto un errore da qualche parte: mi sono imbattuto this benchmark (loop 5 volte per evitare distorsioni jitter) e usato questo metodo di estensione da confrontare con il metodo String.Contains
public static bool QuickContains(this string input, string value)
{
return input.IndexOf(value, 0, input.Length, StringComparison.OrdinalIgnoreCase) >= 0;
}
con il ciclo simile a questo
for (int i = 0; i < 1000000; i++)
{
bool containsStringRegEx = testString.QuickContains("STRING");
}
sw.Stop();
Console.WriteLine("QuickContains: " + sw.ElapsedMilliseconds);
Nel test di benchmark, QuickContains
sembra circa il 50% più veloce di String.Contains
sulla mia macchina.
Aggiornamento 2 (differenza di prestazioni spiegato)
ho notato qualcosa di sleale nel benchmark che spiega molte cose. Lo stesso benchmark era per misurare stringhe maiuscole e minuscole, ma dal momento che String.Contains
è in grado di eseguire solo ricerche sensibili al maiuscolo/minuscolo, è stato incluso il metodo ToUpper
. Ciò potrebbe distorcere i risultati, non in termini di output finale, ma almeno in termini di semplice misurazione delle prestazioni di String.Contains
in ricerche non sensibili al maiuscolo/minuscolo.
Così ora, se io uso questo metodo di estensione
public static bool QuickContains(this string input, string value)
{
return input.IndexOf(value, 0, input.Length, StringComparison.Ordinal) >= 0;
}
uso StringComparison.Ordinal
nel 2 di sovraccarico IndexOf
chiamata e rimuovere ToUpper
, il metodo QuickContains
diventa in realtà la più lenta. IndexOf
e Contains
sono praticamente alla pari in termini di prestazioni. Quindi chiaramente era la chiamata ToUpper
che alterava i risultati del perché c'era una tale discrepanza tra Contains
e IndexOf
.
Non so perché il metodo di estensione QuickContains
è diventato il più lento.(Probabilmente correlato al fatto che lo Contains
ha l'attributo [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
?).
Domanda rimane ancora il motivo per cui il metodo di sovraccarico a 4 non viene chiamato direttamente ma sembra che le prestazioni non siano influenzate (come Adrian e Delnan hanno sottolineato nei commenti) dalla decisione.
E 'possibile che la chiamata al metodo sarà inline dal compilatore, in modo che qualsiasi le occorrenze di 'String.Contains (valore stringa)' possono già essere riscritte nella versione più complessa al momento in cui il codice viene eseguito (lasciando l'unico motivo essere il vantaggio che si menziona, senza svantaggi). Tuttavia, questa è ovviamente solo una congettura. –
Questa è una buona idea. Ho appena provato il benchmarking creando un metodo personalizzato 'Contains' che chiama direttamente il sovraccarico finale e ha finito per essere il 50% più veloce del metodo' Contains' esistente, quindi c'è un notevole riscontro di prestazioni (anche se piccolo in termini assoluti; 200ms oltre 1m di loop). – keyboardP
@keyboardP Trovo che sia un po 'difficile da credere; anche la più semplice euristica in linea e il più semplice inliner dovrebbero rendere le due varianti indistinguibili. Sei sicuro di non aver commesso [errori di benchmarking] (http://tech.pro/blog/1293/c-performance-benchmark-mistakes-part-one)? – delnan