Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto článku se dozvíte o knihovně Microsoft.Extensions.Primitives . Primitiva v tomto článku se nezaměňují s primitivními typy rozhraní .NET z seznamu BCL nebo s primitivními typy jazyka C#. Místo toho typy v rámci primitivní knihovny slouží jako stavební bloky některých balíčků NuGet periferních rozhraní .NET, například:
Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.FileExtensionsMicrosoft.Extensions.FileProviders.CompositeMicrosoft.Extensions.FileProviders.PhysicalMicrosoft.Extensions.Logging.EventSourceMicrosoft.Extensions.OptionsSystem.Text.Json
Změna oznámení
Šíření oznámení, když dojde ke změně, je základním konceptem programování. Pozorovaný stav objektu se často může změnit. Když dojde ke změně, lze implementace Microsoft.Extensions.Primitives.IChangeToken rozhraní použít k informování zúčastněných stran o této změně. Dostupné implementace jsou následující:
Jako vývojář můžete také implementovat vlastní typ. Rozhraní IChangeToken definuje několik vlastností:
- IChangeToken.HasChanged: Získá hodnotu, která označuje, zda došlo ke změně.
-
IChangeToken.ActiveChangeCallbacks: Označuje, jestli token proaktivně vyvolá zpětné volání. Pokud
false, příjemce tokenu se musí dotazovatHasChanged, aby zjistil změny.
Funkce založené na instancích
Podívejte se na následující příklad použití CancellationChangeToken:
CancellationTokenSource cancellationTokenSource = new();
CancellationChangeToken cancellationChangeToken = new(cancellationTokenSource.Token);
Console.WriteLine($"HasChanged: {cancellationChangeToken.HasChanged}");
static void callback(object? _) =>
Console.WriteLine("The callback was invoked.");
using (IDisposable subscription =
cancellationChangeToken.RegisterChangeCallback(callback, null))
{
cancellationTokenSource.Cancel();
}
Console.WriteLine($"HasChanged: {cancellationChangeToken.HasChanged}\n");
// Outputs:
// HasChanged: False
// The callback was invoked.
// HasChanged: True
V předchozím příkladu se vytvoří instance CancellationTokenSource a Token se předá konstruktoru CancellationChangeToken. Počáteční stav HasChanged je zapsán do konzoly. Při vyvolání zpětného volání se vytvoří Action<object?> callback, který zapisuje do konzoly. Metoda tokenu RegisterChangeCallback(Action<Object>, Object) je volána při callback. V rámci using příkazu se cancellationTokenSource zruší. Tím se aktivuje zpětné volání a stav HasChanged se znovu zapíše do konzoly.
Pokud potřebujete provést akci z více zdrojů změn, použijte tlačítko CompositeChangeToken. Tato implementace agreguje jeden nebo více tokenů změn a spustí každé zaregistrované zpětné volání přesně jednou, bez ohledu na počet aktivací změny. Představte si následující příklad:
CancellationTokenSource firstCancellationTokenSource = new();
CancellationChangeToken firstCancellationChangeToken = new(firstCancellationTokenSource.Token);
CancellationTokenSource secondCancellationTokenSource = new();
CancellationChangeToken secondCancellationChangeToken = new(secondCancellationTokenSource.Token);
CancellationTokenSource thirdCancellationTokenSource = new();
CancellationChangeToken thirdCancellationChangeToken = new(thirdCancellationTokenSource.Token);
var compositeChangeToken =
new CompositeChangeToken(
new IChangeToken[]
{
firstCancellationChangeToken,
secondCancellationChangeToken,
thirdCancellationChangeToken
});
static void callback(object? state) =>
Console.WriteLine($"The {state} callback was invoked.");
// 1st, 2nd, 3rd, and 4th.
compositeChangeToken.RegisterChangeCallback(callback, "1st");
compositeChangeToken.RegisterChangeCallback(callback, "2nd");
compositeChangeToken.RegisterChangeCallback(callback, "3rd");
compositeChangeToken.RegisterChangeCallback(callback, "4th");
// It doesn't matter which cancellation source triggers the change.
// If more than one trigger the change, each callback is only fired once.
Random random = new();
int index = random.Next(3);
CancellationTokenSource[] sources = new[]
{
firstCancellationTokenSource,
secondCancellationTokenSource,
thirdCancellationTokenSource
};
sources[index].Cancel();
Console.WriteLine();
// Outputs:
// The 4th callback was invoked.
// The 3rd callback was invoked.
// The 2nd callback was invoked.
// The 1st callback was invoked.
V předchozím kódu jazyka C# se vytvoří a spárují tři CancellationTokenSource instance objektů s odpovídajícími CancellationChangeToken instancemi. Složený token je instancován předáním pole tokenů jako parametr konstruktoru CompositeChangeToken. Vytvoří se Action<object?> callback, ale tentokrát se použije objekt state a zapíše se do konzoly jako formátovaná zpráva. Zpětné volání je registrováno čtyřikrát, každý s mírně odlišným argumentem stavového objektu. Kód používá pseudonáhodný generátor čísel k výběru jednoho ze zdrojů tokenů změn (nezáleží na tom, který z nich) a zavolá jeho Cancel() metodu. Tím se tato změna aktivuje a invokuje každý registrovaný zpětný volání pouze jednou.
Alternativní static přístup
Jako alternativu k volání RegisterChangeCallbackmůžete použít Microsoft.Extensions.Primitives.ChangeToken statickou třídu. Vezměte v úvahu následující model spotřeby:
CancellationTokenSource cancellationTokenSource = new();
CancellationChangeToken cancellationChangeToken = new(cancellationTokenSource.Token);
IChangeToken producer()
{
// The producer factory should always return a new change token.
// If the token's already fired, get a new token.
if (cancellationTokenSource.IsCancellationRequested)
{
cancellationTokenSource = new();
cancellationChangeToken = new(cancellationTokenSource.Token);
}
return cancellationChangeToken;
}
void consumer() => Console.WriteLine("The callback was invoked.");
using (ChangeToken.OnChange(producer, consumer))
{
cancellationTokenSource.Cancel();
}
// Outputs:
// The callback was invoked.
Podobně jako v předchozích příkladech budete potřebovat implementaci IChangeToken , která je vytvořena pomocí changeTokenProducer. Producent je definován jako Func<IChangeToken> a očekává se, že se vrátí nový token při každém vyvolání. Jedná se buď o Action při nepoužití state, nebo o Action<TState>, kde obecný typ TState prochází oznámením o změně.
Tokenizátory řetězců, segmenty a hodnoty
Interakce s řetězci je běžná při vývoji aplikací. Různé reprezentace řetězců se analyzují, rozdělují nebo iterují. Knihovna primitiv nabízí několik typů voleb, které pomáhají lépe optimalizovat a efektivněji pracovat s řetězci. Zvažte následující typy:
- StringSegment: Optimalizovaná reprezentace podřetězce.
-
StringTokenizer: Rozděluje
stringna instanceStringSegment. -
StringValues: Představuje
null, nula, jeden nebo mnoho řetězců efektivním způsobem.
Typ StringSegment
V této části se dozvíte o optimalizované reprezentaci podřetězce, který je znám jako StringSegmentstruct typu. Představte si následující příklad kódu jazyka C#, který ukazuje některé vlastnosti StringSegment a metodu AsSpan :
var segment =
new StringSegment(
"This a string, within a single segment representation.",
14, 25);
Console.WriteLine($"Buffer: \"{segment.Buffer}\"");
Console.WriteLine($"Offset: {segment.Offset}");
Console.WriteLine($"Length: {segment.Length}");
Console.WriteLine($"Value: \"{segment.Value}\"");
Console.Write("Span: \"");
foreach (char @char in segment.AsSpan())
{
Console.Write(@char);
}
Console.Write("\"\n");
// Outputs:
// Buffer: "This a string, within a single segment representation."
// Offset: 14
// Length: 25
// Value: " within a single segment "
// " within a single segment "
Předchozí kód vytvoří instanci StringSegment na základě dané hodnoty string, prvku offset a prvku length.
StringSegment.Buffer je původní řetězcový argument a StringSegment.Value je podřetězec založený na hodnotách StringSegment.Offset a StringSegment.Length.
Struktura StringSegment poskytuje mnoho metod pro interakci se segmentem.
Typ StringTokenizer
Objekt StringTokenizer je typ struktury, který tokenizuje string do původních instancí StringSegment. Tokenizace velkých řetězců obvykle zahrnuje rozdělení řetězce od sebe a iterování nad ním. Jak již bylo řečeno, String.Split pravděpodobně přijde na mysl. Tato rozhraní API jsou podobná, ale obecně StringTokenizer poskytují lepší výkon. Nejprve zvažte následující příklad:
var tokenizer =
new StringTokenizer(
s_nineHundredAutoGeneratedParagraphsOfLoremIpsum,
new[] { ' ' });
foreach (StringSegment segment in tokenizer)
{
// Interact with segment
}
V předchozím kódu se vytvoří instance StringTokenizer typu s 900 automaticky vygenerovanými Lorem Ipsum odstavci textu a pole s jednou hodnotou prázdného znaku ' '. Každá hodnota v tokenizátoru je reprezentována jako StringSegment. Kód iteruje segmenty, což příjemci umožňuje interakci s jednotlivými segmentsegmenty .
Porovnání srovnávacích testů StringTokenizerstring.Split
S různými způsoby řezů a dilací řetězců je vhodné porovnat dvě metody srovnávacím testem. Při použití balíčku NuGet BenchmarkDotNet zvažte následující dvě metody srovnávacího testu:
Pomocí StringTokenizer:
StringBuilder buffer = new(); var tokenizer = new StringTokenizer( s_nineHundredAutoGeneratedParagraphsOfLoremIpsum, new[] { ' ', '.' }); foreach (StringSegment segment in tokenizer) { buffer.Append(segment.Value); }Pomocí String.Split:
StringBuilder buffer = new(); string[] tokenizer = s_nineHundredAutoGeneratedParagraphsOfLoremIpsum.Split( new[] { ' ', '.' }); foreach (string segment in tokenizer) { buffer.Append(segment); }
Obě metody vypadají podobně v oblasti rozhraní API a oba dokážou rozdělit velký řetězec na bloky dat. Níže uvedené výsledky srovnávacího testu ukazují, že StringTokenizer přístup je téměř třikrát rychlejší, ale výsledky se mohou lišit. Stejně jako u všech aspektů výkonu byste měli vyhodnotit konkrétní případ použití.
| metoda | Střední hodnota | Chyba | Směrodatná odchylka | Koeficient |
|---|---|---|---|---|
| Tokenizátor | 3.315 ms | 0.0659 ms | 0.0705 ms | 0.32 |
| Rozděleno | 10.257 ms | 0.2018 ms | 0.2552 ms | 1.00 |
Legenda
- Střední hodnota: Aritmetický průměr všech měření
- Chyba: Polovina intervalu spolehlivosti 99,9 %
- Směrodatná odchylka: Směrodatná odchylka všech měření
- Medián: Hodnota oddělující vyšší polovinu všech měření (50. percentil)
- Poměr: Střední hodnota rozdělení poměru (aktuální/referenční hodnota)
- Směrodatná odchylka poměru: Směrodatná odchylka rozdělení poměru (aktuální/základní hodnota)
- 1 ms: 1 Milisekunda (0,001 s)
Další informace o srovnávacích testech pomocí .NET najdete v tématu BenchmarkDotNet.
Typ StringValues
Objekt StringValues je typ struct, který efektivně představuje null, a to nula, jeden nebo mnoho řetězců. Typ StringValues lze vytvořit pomocí některé z následujících syntaxí: string? nebo string?[]?. Při použití textu z předchozího příkladu zvažte následující kód jazyka C#:
StringValues values =
new(s_nineHundredAutoGeneratedParagraphsOfLoremIpsum.Split(
new[] { '\n' }));
Console.WriteLine($"Count = {values.Count:#,#}");
foreach (string? value in values)
{
// Interact with the value
}
// Outputs:
// Count = 1,799
Předchozí kód vytvoří instanci objektu StringValues s polem řetězcových hodnot.
StringValues.Count je zapsán do konzole.
Typ StringValues je implementace následujících typů kolekcí:
IList<string>ICollection<string>IEnumerable<string>IEnumerableIReadOnlyList<string>IReadOnlyCollection<string>
V takovém případě lze iterovat a s každým value lze podle potřeby pracovat.