Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ebben a cikkben megismerheti a Microsoft.Extensions.Primitives kódtárat . A cikkben szereplő primitívek nem tévesztendők össze a BCL-ből származó .NET primitív típusokkal vagy a C# nyelvével. Ehelyett a primitív kódtárban lévő típusok a periféria .NET NuGet-csomagjainak építőelemei, például:
Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.FileExtensionsMicrosoft.Extensions.FileProviders.CompositeMicrosoft.Extensions.FileProviders.PhysicalMicrosoft.Extensions.Logging.EventSourceMicrosoft.Extensions.OptionsSystem.Text.Json
Értesítések módosítása
Az értesítések propagálása változás esetén a programozás alapvető fogalma. Az objektumok megfigyelt állapota gyakran változik. Ha változás történik, a felület implementációi felhasználhatók az Microsoft.Extensions.Primitives.IChangeToken érdekelt felek értesítésére az említett változásról. Az elérhető implementációk a következők:
Fejlesztőként ön is szabadon implementálhatja saját típusát. A IChangeToken felület néhány tulajdonságot határoz meg:
- IChangeToken.HasChanged: Olyan értéket kap, amely jelzi, hogy történt-e változás.
-
IChangeToken.ActiveChangeCallbacks: Azt jelzi, hogy a token proaktívan kezdeményezi-e a visszahívásokat. Ha
false, a jogkivonat-fogyasztónak figyelemmel kell kísérnieHasChangeda változások észleléséhez.
Példányalapú funkciók
Vegye figyelembe a következő példa használatát: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
Az előző példában egy CancellationTokenSource példányosodik, és annak Token példányát adják át a CancellationChangeToken konstruktornak. A rendszer a kezdeti állapotot HasChanged a konzolra írja. Egy Action<object?> callback jön létre, amely akkor ír a konzolra, amikor a visszahívás meghívásra kerül. A jogkivonat RegisterChangeCallback(Action<Object>, Object) metódusát meghívják, a callback alapján. A using utasításon belül a cancellationTokenSource törlésre kerül. Ez aktiválja a visszahívást, és az állapot HasChanged ismét meg lesz írva a konzolra.
Ha több változási forrásból kell műveletet elvégeznie, használja a CompositeChangeToken. Ez a megvalósítás egy vagy több változásértesítést összesít, és minden regisztrált visszahívást pontosan egy alkalommal hajt végre, függetlenül attól, hogy a módosítás hányszor aktiválódik. Vegyük a következő példát:
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.
Az előző C#-kódban három CancellationTokenSource objektumpéldány jön létre és párosítva a megfelelő CancellationChangeToken példányokkal. Az összetett jogkivonat példányosítása a jogkivonatok tömbjének a CompositeChangeToken konstruktorhoz való átadásával történik. A Action<object?> callback létrejön, de ezúttal a state objektumot használják, és formázott üzenetként írják a konzolra. A visszahívás négy alkalommal van regisztrálva, mindegyikhez egy kissé eltérő állapotobjektum-argumentum tartozik. A kód egy pszeudo-véletlenszerű számgenerátor használatával választja ki a változási jogkivonat forrásainak egyikét (nem számít, melyiket), és meghívja annak metódusát Cancel() . Ez aktiválja a módosítást, és minden regisztrált visszahívást pontosan egyszer hív meg.
Alternatív static megközelítés
A hívás RegisterChangeCallbackalternatívaként használhatja a statikus osztályt Microsoft.Extensions.Primitives.ChangeToken . Vegye figyelembe a következő fogyasztási mintát:
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.
A korábbi példákhoz hasonlóan szüksége lesz egy olyan implementációra IChangeToken, amelyet a changeTokenProducer. A gyártó Func<IChangeToken>-ként van definiálva, és várható, hogy minden meghíváskor új jogkivonatot ad vissza.
consumer lehet egy Action, amikor nem használja a state-t, vagy egy Action<TState>, ahol az általános típus TState áthalad a változásjelzésen.
Sztringtokenizálók, szegmensek és értékek
A sztringekkel való interakció gyakori az alkalmazásfejlesztésben. A karakterláncok különféle ábrázolásait elemezhetjük, feloszthatjuk vagy iterálhatunk rajtuk. A primitívek kódtára kínál néhány választható típust, amelyek segítenek optimalizáltabbá és hatékonyabbá tenni a sztringekkel való interakciót. Vegye figyelembe a következő típusokat:
- StringSegment: Egy karakterlánc részleteinek optimalizált ábrázolása.
-
StringTokenizer: Tokenekre bont
stringStringSegmentpéldányt. -
StringValues: Hatékonyan jelöli
null, a nulla, egy vagy több karakterláncot.
A StringSegment típus
Ebben a szakaszban megismerheti a típusként StringSegmentstruct ismert alsztringek optimalizált ábrázolását. Tekintse meg a következő C#-kód példáját, amely néhány StringSegment tulajdonságot és metódust AsSpan mutat be:
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 "
Az előző kód példányosítja a StringSegment egy string értéket, egy offset és egy length alapján. Az StringSegment.Buffer az eredeti sztringargumentum, és a StringSegment.Value részsztring a StringSegment.Offset és StringSegment.Length értékek alapján jön létre.
A StringSegment szerkezet számos módszert kínál a szegmensekkel való interakcióhoz.
A StringTokenizer típus
Az StringTokenizer objektum egy struktúratípus, amely a string-et StringSegment példányokra bontja. A nagy karakterláncok tokenizálása általában magában foglalja a karakterlánc szétválasztását és iterálását. Ha ez így van, String.Split valószínűleg eszembe jut. Ezek az API-k hasonlóak, de általában StringTokenizer jobb teljesítményt nyújtanak. Először vegye figyelembe a következő példát:
var tokenizer =
new StringTokenizer(
s_nineHundredAutoGeneratedParagraphsOfLoremIpsum,
new[] { ' ' });
foreach (StringSegment segment in tokenizer)
{
// Interact with segment
}
A korábbi kódban létrehozunk egy StringTokenizer típusú példányt, 900 automatikusan generált Lorem Ipsum szöveg bekezdés és egy szóköz karaktert tartalmazó ' ' tömb alapján. A tokenizer minden egyes értékét egy StringSegment jelöli. A kód iterálja a szegmenseket, lehetővé téve a felhasználó számára az egyes segment.
Összehasonlítás a StringTokenizer teljesítménymutatóval string.Split
A sztringek szeletelésének és feldarabolásának különböző módjaival célszerű két módszert összehasonlítani egy referenciaértékkel. A BenchmarkDotNet NuGet-csomag használatával fontolja meg a következő két benchmark metódust:
Használva: StringTokenizer
StringBuilder buffer = new(); var tokenizer = new StringTokenizer( s_nineHundredAutoGeneratedParagraphsOfLoremIpsum, new[] { ' ', '.' }); foreach (StringSegment segment in tokenizer) { buffer.Append(segment.Value); }Használva: String.Split
StringBuilder buffer = new(); string[] tokenizer = s_nineHundredAutoGeneratedParagraphsOfLoremIpsum.Split( new[] { ' ', '.' }); foreach (string segment in tokenizer) { buffer.Append(segment); }
Mindkét metódus hasonlóan néz ki az API felületén, és mindkettő képes nagy sztringeket darabkákra osztani. Az alábbi teljesítményteszt eredményei azt mutatják, hogy a StringTokenizer megközelítés közel háromszor gyorsabb, de az eredmények eltérőek lehetnek. Mint minden teljesítménybeli szempontnál, a konkrét használati esetet is ki kell értékelnie.
| Metódus | Középérték | Hiba | StdDev | Arány |
|---|---|---|---|---|
| Tokenizáló | 3,315 ms | 0,0659 ms | 0,0705 ms | 0.32 |
| Szakít | 10,257 ms | 0,2018 ms | 0,2552 ms | 1,00 |
Legenda
- Középérték: Az összes mérés számtani középértéke
- Hiba: A 99,9%-os megbízhatósági intervallum fele
- Szórás: Az összes mérés standard szórása
- Medián: Az összes mérés felső felét elválasztó érték (50. percentilis)
- Arány: Az arányeloszlás középértéke (aktuális/alapkonfiguráció)
- Arány szórása: Az arányeloszlás szórása (aktuális/alapállapot)
- 1 ms: 1 ezredmásodperc (0,001 mp)
A .NET-hez való teljesítménytesztről további információt a BenchmarkDotNetben talál.
A StringValues típus
Az StringValues objektum olyan struct típus, amely hatékonyan jelöl null, nulla, egy vagy több sztringet. A StringValues típus a következő szintaxisok egyikével hozható létre: string? vagy string?[]?. Az előző példa szövegét használva vegye figyelembe a következő C#-kódot:
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
Az előző kód egy sztringértékek tömbje alapján példányosít egy StringValues objektumot. A StringValues.Count rendszer a konzolra írja.
A StringValues típus a következő gyűjteménytípusok implementációja:
IList<string>ICollection<string>IEnumerable<string>IEnumerableIReadOnlyList<string>IReadOnlyCollection<string>
Ennek megfelelően át lehet iterálni, és mindegyik value szükség szerint használható.