Projectiebewerkingen (C#)
Projectie verwijst naar de werking van het transformeren van een object in een nieuwe vorm die vaak alleen bestaat uit die eigenschappen die vervolgens worden gebruikt. Met behulp van projectie kunt u een nieuw type maken dat is gebouwd op basis van elk object. U kunt een eigenschap projecten en er een wiskundige functie op uitvoeren. U kunt het oorspronkelijke object ook projecten zonder het te wijzigen.
Belangrijk
In deze voorbeelden wordt een System.Collections.Generic.IEnumerable<T> gegevensbron gebruikt. Gegevensbronnen op System.Linq.IQueryProvider basis van het gebruik van System.Linq.IQueryable<T> gegevensbronnen en expressiestructuren. Expressiestructuren hebben beperkingen voor de toegestane C#-syntaxis. Bovendien kan elke IQueryProvider
gegevensbron, zoals EF Core , meer beperkingen opleggen. Raadpleeg de documentatie voor uw gegevensbron.
De standaardqueryoperatormethoden die projectie uitvoeren, worden weergegeven in de volgende sectie.
Methoden
Methodenamen | Beschrijving | C#-queryexpressiesyntaxis | Meer informatie |
---|---|---|---|
Select | Projecten die zijn gebaseerd op een transformatiefunctie. | select |
Enumerable.Select Queryable.Select |
SelectMany | Projectenreeksen van waarden die zijn gebaseerd op een transformatiefunctie en vervolgens platmaken in één reeks. | Meerdere from componenten gebruiken |
Enumerable.SelectMany Queryable.SelectMany |
Postcode | Produceert een reeks tuples met elementen uit 2-3 opgegeven reeksen. | Niet van toepassing. | Enumerable.Zip Queryable.Zip |
Select
In het volgende voorbeeld wordt de select
component gebruikt om de eerste letter van elke tekenreeks in een lijst met tekenreeksen te projecteren.
List<string> words = ["an", "apple", "a", "day"];
var query = from word in words
select word.Substring(0, 1);
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
De equivalente query met behulp van de methodesyntaxis wordt weergegeven in de volgende code:
List<string> words = ["an", "apple", "a", "day"];
var query = words.Select(word => word.Substring(0, 1));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
a
a
a
d
*/
SelectMany
In het volgende voorbeeld worden meerdere from
componenten gebruikt om elk woord uit elke tekenreeks te projecteren in een lijst met tekenreeksen.
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = from phrase in phrases
from word in phrase.Split(' ')
select word;
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
De equivalente query met behulp van de methodesyntaxis wordt weergegeven in de volgende code:
List<string> phrases = ["an apple a day", "the quick brown fox"];
var query = phrases.SelectMany(phrases => phrases.Split(' '));
foreach (string s in query)
{
Console.WriteLine(s);
}
/* This code produces the following output:
an
apple
a
day
the
quick
brown
fox
*/
De SelectMany
methode kan ook de combinatie vormen van het vergelijken van elk item in de eerste reeks met elk item in de tweede reeks:
var query = from number in numbers
from letter in letters
select (number, letter);
foreach (var item in query)
{
Console.WriteLine(item);
}
De equivalente query met behulp van de methodesyntaxis wordt weergegeven in de volgende code:
var method = numbers
.SelectMany(number => letters,
(number, letter) => (number, letter));
foreach (var item in method)
{
Console.WriteLine(item);
}
Zip
Er zijn verschillende overbelastingen voor de Zip
projectieoperator. Zip
Alle methoden werken aan reeksen van twee of meer mogelijk heterogene typen. De eerste twee overbelastingen retourneren tuples, met het bijbehorende positionele type uit de opgegeven reeksen.
Houd rekening met de volgende verzamelingen:
// An int array with 7 elements.
IEnumerable<int> numbers = [1, 2, 3, 4, 5, 6, 7];
// A char array with 6 elements.
IEnumerable<char> letters = ['A', 'B', 'C', 'D', 'E', 'F'];
Gebruik de operator om deze reeksen samen te Enumerable.Zip<TFirst,TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>) projecteren:
foreach ((int number, char letter) in numbers.Zip(letters))
{
Console.WriteLine($"Number: {number} zipped with letter: '{letter}'");
}
// This code produces the following output:
// Number: 1 zipped with letter: 'A'
// Number: 2 zipped with letter: 'B'
// Number: 3 zipped with letter: 'C'
// Number: 4 zipped with letter: 'D'
// Number: 5 zipped with letter: 'E'
// Number: 6 zipped with letter: 'F'
Belangrijk
De resulterende reeks van een zip-bewerking is nooit langer dan de kortste reeks. De numbers
en letters
verzamelingen verschillen in lengte en de resulterende reeks laat het laatste element van de numbers
verzameling weg, omdat er niets te zippen is.
De tweede overbelasting accepteert een third
reeks. Laten we een andere verzameling maken, namelijk emoji
:
// A string array with 8 elements.
IEnumerable<string> emoji = [ "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯"];
Gebruik de operator om deze reeksen samen te Enumerable.Zip<TFirst,TSecond,TThird>(IEnumerable<TFirst>, IEnumerable<TSecond>, IEnumerable<TThird>) projecteren:
foreach ((int number, char letter, string em) in numbers.Zip(letters, emoji))
{
Console.WriteLine(
$"Number: {number} is zipped with letter: '{letter}' and emoji: {em}");
}
// This code produces the following output:
// Number: 1 is zipped with letter: 'A' and emoji: 🤓
// Number: 2 is zipped with letter: 'B' and emoji: 🔥
// Number: 3 is zipped with letter: 'C' and emoji: 🎉
// Number: 4 is zipped with letter: 'D' and emoji: 👀
// Number: 5 is zipped with letter: 'E' and emoji: ⭐
// Number: 6 is zipped with letter: 'F' and emoji: 💜
Net als bij de vorige overbelasting projecteert de Zip
methode een tuple, maar deze keer met drie elementen.
De derde overbelasting accepteert een Func<TFirst, TSecond, TResult>
argument dat fungeert als een resultatenkiezer. U kunt een nieuwe resulterende reeks projecteert van de reeksen die worden gezipt.
foreach (string result in
numbers.Zip(letters, (number, letter) => $"{number} = {letter} ({(int)letter})"))
{
Console.WriteLine(result);
}
// This code produces the following output:
// 1 = A (65)
// 2 = B (66)
// 3 = C (67)
// 4 = D (68)
// 5 = E (69)
// 6 = F (70)
Met de voorgaande Zip
overbelasting wordt de opgegeven functie toegepast op de bijbehorende elementen numbers
en letter
wordt een reeks string
resultaten geproduceerd.
Select
Versus SelectMany
Het werk van beide Select
en SelectMany
is het produceren van een resultaatwaarde (of waarden) van bronwaarden. Select
produceert één resultaatwaarde voor elke bronwaarde. Het algehele resultaat is daarom een verzameling met hetzelfde aantal elementen als de bronverzameling. Produceert daarentegen SelectMany
één algemeen resultaat dat samengevoegde subverzamelingen van elke bronwaarde bevat. De transformatiefunctie die als argument SelectMany
wordt doorgegeven, moet een opsommingsvolgorde van waarden retourneren voor elke bronwaarde. SelectMany
voegt deze enumerable reeksen samen om één grote reeks te maken.
In de volgende twee illustraties ziet u het conceptuele verschil tussen de acties van deze twee methoden. In elk geval wordt ervan uitgegaan dat de functie selector (transformatie) de matrix met bloemen uit elke bronwaarde selecteert.
In deze afbeelding ziet u hoe Select
een verzameling met hetzelfde aantal elementen wordt geretourneerd als de bronverzameling.
In deze afbeelding ziet u hoe SelectMany
u de tussenliggende reeks matrices samenvoegt in één uiteindelijke resultaatwaarde die elke waarde van elke tussenliggende matrix bevat.
Voorbeeld van code
In het volgende voorbeeld wordt het gedrag van Select
en SelectMany
. De code maakt een 'boeket' van bloemen door de items uit elke lijst met bloemnamen in de bronverzameling te nemen. In het volgende voorbeeld is de 'enkele waarde' die door de transformatiefunctie Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>) wordt gebruikt, een verzameling waarden. In dit voorbeeld is de extra foreach
lus vereist om elke tekenreeks in elke subsequence te inventariseren.
class Bouquet
{
public required List<string> Flowers { get; init; }
}
static void SelectVsSelectMany()
{
List<Bouquet> bouquets =
[
new Bouquet { Flowers = ["sunflower", "daisy", "daffodil", "larkspur"] },
new Bouquet { Flowers = ["tulip", "rose", "orchid"] },
new Bouquet { Flowers = ["gladiolis", "lily", "snapdragon", "aster", "protea"] },
new Bouquet { Flowers = ["larkspur", "lilac", "iris", "dahlia"] }
];
IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);
Console.WriteLine("Results by using Select():");
// Note the extra foreach loop here.
foreach (IEnumerable<string> collection in query1)
{
foreach (string item in collection)
{
Console.WriteLine(item);
}
}
Console.WriteLine("\nResults by using SelectMany():");
foreach (string item in query2)
{
Console.WriteLine(item);
}
}