C#-funktioner som stöder LINQ
Frågeuttryck
Frågeuttryck använder en deklarativ syntax som liknar SQL eller XQuery för att köra frågor mot System.Collections.Generic.IEnumerable<T> samlingar. Vid kompileringen konverteras frågesyntaxen till metodanrop till en LINQ-providers implementering av standardfrågemetoderna. Program styr de vanliga frågeoperatorer som finns i omfånget genom att ange lämpligt namnområde med ett using
direktiv. Följande frågeuttryck tar en matris med strängar, grupperar dem enligt det första tecknet i strängen och beställer grupperna.
var query = from str in stringArray
group str by str[0] into stringGroup
orderby stringGroup.Key
select stringGroup;
Implicit inskrivna variabler (var)
Du kan använda var-modifieraren för att instruera kompilatorn att härleda och tilldela typen, enligt följande:
var number = 5;
var name = "Virginia";
var query = from str in stringArray
where str[0] == 'm'
select str;
Variabler som deklareras som var
är starkt inskrivna, precis som variabler vars typ du uttryckligen anger. Användningen av var
gör det möjligt att skapa anonyma typer, men bara för lokala variabler. Mer information finns i Implicit inskrivna lokala variabler.
Initierare för objekt och samling
Initiatorer för objekt och samling gör det möjligt att initiera objekt utan att uttryckligen anropa en konstruktor för objektet. Initialiserare används vanligtvis i frågeuttryck när de projicerar källdata till en ny datatyp. Om vi antar en klass med namnet Customer
med offentliga Name
egenskaper och Phone
egenskaper kan objektinitieraren användas som i följande kod:
var cust = new Customer { Name = "Mike", Phone = "555-1212" };
Om du fortsätter med din Customer
klass antar du att det finns en datakälla med namnet IncomingOrders
, och att du för varje order med en stor OrderSize
, vill skapa en ny Customer
baserad av den ordern. En LINQ-fråga kan köras på den här datakällan och använda objektinitiering för att fylla en samling:
var newLargeOrderCustomers = from o in IncomingOrders
where o.OrderSize > 5
select new Customer { Name = o.Name, Phone = o.Phone };
Datakällan kan ha fler egenskaper definierade än Customer
klassen, OrderSize
till exempel , men med objektinitiering formas data som returneras från frågan till önskad datatyp. Du väljer de data som är relevanta för din klass. Som ett resultat har du nu en System.Collections.Generic.IEnumerable<T> fylld med de nya Customer
s du ville ha. Föregående exempel kan också skrivas i LINQ:s metodsyntax:
var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone });
Från och med C# 12 kan du använda ett samlingsuttryck för att initiera en samling.
Mer information finns i:
Anonyma typer
Kompilatorn skapar en anonym typ. Typnamnet är endast tillgängligt för kompilatorn. Anonyma typer är ett bekvämt sätt att gruppera en uppsättning egenskaper tillfälligt i ett frågeresultat utan att behöva definiera en separat namngiven typ. Anonyma typer initieras med ett nytt uttryck och en objektinitierare, som du ser här:
select new {name = cust.Name, phone = cust.Phone};
Från och med C# 7 kan du använda tupplar för att skapa namnlösa typer.
Tilläggsmetoder
En tilläggsmetod är en statisk metod som kan associeras med en typ, så att den kan anropas som om det vore en instansmetod för typen. Med den här funktionen kan du i praktiken "lägga till" nya metoder i befintliga typer utan att ändra dem. Standardfrågeoperatorerna är en uppsättning tilläggsmetoder som tillhandahåller LINQ-frågefunktioner för alla typer som implementerar IEnumerable<T>.
Lambda-uttryck
Ett lambda-uttryck är en infogad funktion som använder operatorn =>
för att separera indataparametrar från funktionstexten och kan konverteras vid kompilering till ett ombud eller ett uttrycksträd. I LINQ-programmering får du lambda-uttryck när du gör direkta metodanrop till standardfrågeoperatorerna.
Uttryck som data
Frågeobjekt är skrivbara, vilket innebär att du kan returnera en fråga från en metod. Objekt som representerar frågor lagrar inte den resulterande samlingen, utan snarare stegen för att generera resultatet när det behövs. Fördelen med att returnera frågeobjekt från metoder är att de kan bestå eller ändras ytterligare. Därför måste ett returvärde eller out
en parameter för en metod som returnerar en fråga också ha den typen. Om en metod materialiserar en fråga till en betong List<T> eller Array typ returneras frågeresultatet i stället för själva frågan. En frågevariabel som returneras från en metod kan fortfarande bestå eller ändras.
I följande exempel returnerar den första metoden QueryMethod1
en fråga som ett returvärde, och den andra metoden QueryMethod2
returnerar en fråga som en out
parameter (returnQ
i exemplet). I båda fallen är det en fråga som returneras, inte frågeresultat.
IEnumerable<string> QueryMethod1(int[] ints) =>
from i in ints
where i > 4
select i.ToString();
void QueryMethod2(int[] ints, out IEnumerable<string> returnQ) =>
returnQ =
from i in ints
where i < 4
select i.ToString();
int[] nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var myQuery1 = QueryMethod1(nums);
Frågan myQuery1
körs i följande foreach-loop.
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}
Vila muspekaren över myQuery1
för att se dess typ.
Du kan också köra frågan som returneras direkt QueryMethod1
, utan att använda myQuery1
.
foreach (var s in QueryMethod1(nums))
{
Console.WriteLine(s);
}
Vila muspekaren över anropet för att QueryMethod1
se dess returtyp.
QueryMethod2
returnerar en fråga som värdet för parametern out
:
QueryMethod2(nums, out IEnumerable<string> myQuery2);
// Execute the returned query.
foreach (var s in myQuery2)
{
Console.WriteLine(s);
}
Du kan ändra en fråga med hjälp av frågesammansättning. I det här fallet används det tidigare frågeobjektet för att skapa ett nytt frågeobjekt. Det här nya objektet returnerar andra resultat än det ursprungliga frågeobjektet.
myQuery1 =
from item in myQuery1
orderby item descending
select item;
// Execute the modified query.
Console.WriteLine("\nResults of executing modified myQuery1:");
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}