Sök…


Introduktion

LINQ är en förkortning som står för L anguage IN tegrated Q uery. Det är ett koncept som integrerar ett frågespråk genom att erbjuda en konsekvent modell för att arbeta med data över olika typer av datakällor och format; du använder samma grundläggande kodningsmönster för att fråga och omvandla data i XML-dokument, SQL-databaser, ADO.NET-databaser, .NET-samlingar och alla andra format som en LINQ-leverantör är tillgänglig för.

Syntax

  • Frågesyntax:

    • från <intervallvariabel> i <samling>
    • [från <intervallvariabel> i <samling>, ...]
    • <filter, sammanfogning, gruppering, aggregerade operatörer, ...> <lambda expression>
    • <välj eller gruppBy operator> <formulera resultatet>
  • Metodsyntax:

    • Enumerable.Aggregate (func)
    • Enumerable.Aggregate (seed, func)
    • Enumerable.Aggregate (seed, func, resultSelector)
    • Enumerable.All (predikat)
    • Enumerable.Any ()
    • Enumerable.Any (predikat)
    • Enumerable.AsEnumerable ()
    • Enumerable.Average ()
    • Enumerable.Average (väljare)
    • Enumerable.Cast <Resultat> ()
    • Enumerable.Concat (andra)
    • Enumerable.Contains (värde)
    • Antalet.Innehåller (värde, jämförare)
    • Enumerable.Count ()
    • Enumerable.Count (predikat)
    • Enumerable.DefaultIfEmpty ()
    • Enumerable.DefaultIfEmpty (default)
    • Enumerable.Distinct ()
    • Enumerable.Distinct (Comparer)
    • Enumerable.ElementAt (index)
    • Enumerable.ElementAtOrDefault (index)
    • Enumerable.Empty ()
    • Enumerable.Except (andra)
    • Enumerable.Except (andra, jämförare)
    • Enumerable.First ()
    • Enumerable.First (predikat)
    • Enumerable.FirstOrDefault ()
    • Enumerable.FirstOrDefault (predikat)
    • Enumerable.GroupBy (keySelector)
    • Enumerable.GroupBy (keySelector, resultSelector)
    • Enumerable.GroupBy (keySelector, elementSelector)
    • Enumerable.GroupBy (keySelector, jämförare)
    • Enumerable.GroupBy (keySelector, resultSelector, jämförare)
    • Enumerable.GroupBy (keySelector, elementSelector, resultSelector)
    • Enumerable.GroupBy (keySelector, elementSelector, jämförare)
    • Enumerable.GroupBy (keySelector, elementSelector, resultSelector, jämförare)
    • Enumerable.Intersect (andra)
    • Antalet. Korsa (andra, jämförare)
    • Enumerable.Go (inner, ytterKeySelector, innerKeySelector, resultSelector)
    • Enumerable.Goin (inner, ytterKeySelector, innerKeySelector, resultSelector, jämförare)
    • Enumerable.Last ()
    • Enumerable.Last (predikat)
    • Enumerable.LastOrDefault ()
    • Enumerable.LastOrDefault (predikat)
    • Enumerable.LongCount ()
    • Enumerable.LongCount (predikat)
    • Enumerable.Max ()
    • Enumerable.Max (väljare)
    • Enumerable.Min ()
    • Enumerable.Min (väljare)
    • Enumerable.OfType <TResult> ()
    • Enumerable.OrderBy (keySelector)
    • Enumerable.OrderBy (keySelector, jämförare)
    • Enumerable.OrderByDescending (keySelector)
    • Enumerable.OrderByDescending (keySelector, jämförare)
    • Enumerable.Range (start, räkna)
    • Antalet. Upprepa (element, räkna)
    • Enumerable.Reverse ()
    • Enumerable.Select (väljare)
    • Enumerable.SelectMany (väljare)
    • Enumerable.SelectMany (collectionSelector, resultSelector)
    • Enumerable.SequenceEqual (andra)
    • Enumerable.SequenceEqual (andra, jämförare)
    • Enumerable.Single ()
    • Enumerable.Single (predikat)
    • Enumerable.SingleOrDefault ()
    • Enumerable.SingleOrDefault (predikat)
    • Enumerable.Skip (count)
    • Enumerable.SkipWhile (predikat)
    • Enumerable.Sum ()
    • Enumerable.Sum (väljare)
    • Enumerable.Take (count)
    • Enumerable.TakeWhile (predikat)
    • orderedEnumerable.ThenBy (keySelector)
    • beställdEnumerable.ThenBy (keySelector, jämförare)
    • orderedEnumerable.ThenByDescending (keySelector)
    • beställdEnumerable.ThenByDescending (keySelector, jämförare)
    • Enumerable.ToArray ()
    • Enumerable.ToDictionary (keySelector)
    • Enumerable.ToDiction (keySelector, elementSelector)
    • Enumerable.ToDiction (keySelector, jämförare)
    • Enumerable.ToDiction (keySelector, elementSelector, jämförare)
    • Enumerable.ToList ()
    • Enumerable.ToLookup (keySelector)
    • Enumerable.ToLookup (keySelector, elementSelector)
    • Enumerable.ToLookup (keySelector, jämförare)
    • Enumerable.ToLookup (keySelector, elementSelector, jämförare)
    • Enumerable.Union (andra)
    • Enumerable.Union (andra, jämförare)
    • Enumerable.Where (predikat)
    • Enumerable.Zip (andra, resultSelector)

Anmärkningar

För att använda LINQ-frågor måste du importera System.Linq .

Metodsyntaxen är mer kraftfull och flexibel, men Query Syntax kan vara enklare och mer bekant. Alla frågor skrivna i frågsyntax översätts till funktionell syntax av kompilatorn, så prestandan är densamma.

Frågaobjekt utvärderas inte förrän de används, så de kan ändras eller läggas till utan prestationsstraff.

Var

Returnerar en delmängd av objekt som det angivna predikatet är sant för dem.

List<string> trees = new List<string>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };

Metodsyntax

// Select all trees with name of length 3
var shortTrees = trees.Where(tree => tree.Length == 3); // Oak, Elm

Frågesyntax

var shortTrees = from tree in trees
                 where tree.Length == 3
                 select tree; // Oak, Elm

Välj - Transformerande element

Välj gör att du kan tillämpa en transformation på varje element i vilken datastruktur som implementerar IEnumerable.

Få det första tecknet i varje sträng i följande lista:

List<String> trees = new List<String>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };

Med vanlig (lambda) syntax

//The below select stament transforms each element in tree into its first character.
IEnumerable<String> initials = trees.Select(tree => tree.Substring(0, 1));
foreach (String initial in initials) {
    System.Console.WriteLine(initial);
}

Produktion:

O
B
B
E
H
M

Live-demonstration på .NET Fiddle

Använda LINQ Query Syntax

initials = from tree in trees
           select tree.Substring(0, 1);

Kedjningsmetoder

Många LINQ-funktioner fungerar båda på en IEnumerable<TSource> och returnerar också en IEnumerable<TResult> . TSource och TResult eventuellt till samma typ beroende på metod i fråga och eventuella funktioner som skickas till den.

Några exempel på detta är

public static IEnumerable<TResult> Select<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, TResult> selector
)

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate
)

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

Medan vissa metodkedjor kan kräva att en hel uppsättning ska arbetas innan den går vidare, drar LINQ fördel av uppskjuten exekvering genom att använda avkastningsavkastning MSDN som skapar en Enumerable och en Enumerator bakom kulisserna. Processen med att kedja i LINQ bygger väsentligen en uppräknbar (iterator) för den ursprungliga uppsättningen - som är uppskjuten - tills den realiseras genom att räkna upp det många .

Detta gör att dessa funktioner kan vara flytande kedjade wiki , där en funktion kan agera direkt på resultatet av en annan. Den här kodstilen kan användas för att utföra många sekvensbaserade operationer i ett enda uttalande.

Till exempel är det möjligt att kombinera Select , Where och OrderBy att transformera, filtrera och sortera en sekvens i en enda sats.

var someNumbers = { 4, 3, 2, 1 };

var processed = someNumbers
        .Select(n => n * 2)   // Multiply each number by 2
        .Where(n => n != 6)   // Keep all the results, except for 6
        .OrderBy(n => n);     // Sort in ascending order

Produktion:

2
4
8

Live-demonstration på .NET Fiddle

Alla funktioner som både förlänger och returnerar den generiska IEnumerable<T> kan användas som kedjade klausuler i ett enda uttalande. Denna stil med flytande programmering är kraftfull och bör beaktas när du skapar dina egna förlängningsmetoder .

Område och upprepa

De statiska metoderna Range och RepeatEnumerable kan användas för att generera enkla sekvenser.

Räckvidd

Enumerable.Range() genererar en sekvens med heltal som ges ett startvärde och ett räkning.

// Generate a collection containing the numbers 1-100 ([1, 2, 3, ..., 98, 99, 100])
var range = Enumerable.Range(1,100);

Live-demonstration på .NET Fiddle

Upprepa

Enumerable.Repeat() genererar en sekvens med upprepande element som ges ett element och antalet upprepningar som krävs.

// Generate a collection containing "a", three times (["a","a","a"])
var repeatedValues = Enumerable.Repeat("a", 3);

Live-demonstration på .NET Fiddle

Hoppa över och ta

Hoppningsmetoden returnerar en samling exklusive ett antal objekt från början av källsamlingen. Antalet exkluderade objekt är antalet som anges som argument. Om det finns mindre objekt i samlingen än som anges i argumentet returneras en tom samling.

Take-metoden returnerar en samling som innehåller ett antal element från början av källsamlingen. Antalet inkluderade objekt är antalet som anges som argument. Om det finns mindre objekt i samlingen än som anges i argumentet kommer den returnerade samlingen att innehålla samma element som källsamlingen.

var values = new [] { 5, 4, 3, 2, 1 };

var skipTwo        = values.Skip(2);         // { 3, 2, 1 }
var takeThree      = values.Take(3);         // { 5, 4, 3 }
var skipOneTakeTwo = values.Skip(1).Take(2); // { 4, 3 }
var takeZero       = values.Take(0);         // An IEnumerable<int> with 0 items

Live-demonstration på .NET Fiddle

Hoppa och ta används vanligtvis tillsammans för att paginera resultat, till exempel:

IEnumerable<T> GetPage<T>(IEnumerable<T> collection, int pageNumber, int resultsPerPage) {
    int startIndex = (pageNumber - 1) * resultsPerPage;
    return collection.Skip(startIndex).Take(resultsPerPage);
}

Varning: LINQ till enheter stöder endast Hoppa över beställda frågor . Om du försöker använda Skip utan att beställa får du en NotSupportedException med meddelandet "Metoden 'Skip' stöds endast för sorterad inmatning i LINQ till enheter. Metoden 'OrderBy' måste kallas före metoden 'Skip'."

Först FirstOrDefault, Last, LastOrDefault, Single och SingleOrDefault

Alla sex metoder returnerar ett enda värde av sekvenstypen och kan kallas med eller utan predikat.

Beroende på antalet element som matchar predicate eller, om inget predicate tillhandahålls, antalet element i källsekvensen, uppträder de enligt följande:

Först()

  • Returnerar det första elementet i en sekvens eller det första elementet som matchar det angivna predicate .
  • Om sekvensen inte innehåller några element kastas en InvalidOperationException med meddelandet: "Sekvens innehåller inga element".
  • Om sekvensen inte innehåller några element som matchar det angivna predicate kastas en InvalidOperationException med meddelandet "Sequence innehåller inget matchande element".

Exempel

// Returns "a":
new[] { "a" }.First();

// Returns "a":
new[] { "a", "b" }.First();

// Returns "b":
new[] { "a", "b" }.First(x => x.Equals("b"));

// Returns "ba":
new[] { "ba", "be" }.First(x => x.Contains("b"));

// Throws InvalidOperationException:
new[] { "ca", "ce" }.First(x => x.Contains("b"));

// Throws InvalidOperationException:
new string[0].First();

Live-demonstration på .NET Fiddle

FirstOrDefault ()

  • Returnerar det första elementet i en sekvens eller det första elementet som matchar det angivna predicate .
  • Om sekvensen inte innehåller några element, eller inga element som matchar det angivna predicate , returnerar standardvärdet för sekvenstypen med hjälp av default(T) .

Exempel

// Returns "a":
new[] { "a" }.FirstOrDefault();

// Returns "a":
new[] { "a", "b" }.FirstOrDefault();

// Returns "b":
new[] { "a", "b" }.FirstOrDefault(x => x.Equals("b"));

// Returns "ba":
new[] { "ba", "be" }.FirstOrDefault(x => x.Contains("b"));

// Returns null:
new[] { "ca", "ce" }.FirstOrDefault(x => x.Contains("b"));

// Returns null:
new string[0].FirstOrDefault();

Live-demonstration på .NET Fiddle

Sista()

  • Returnerar det sista elementet i en sekvens eller det sista elementet som matchar det angivna predicate .
  • Om sekvensen inte innehåller några element kastas en InvalidOperationException med meddelandet "Sekvens innehåller inga element."
  • Om sekvensen inte innehåller några element som matchar det angivna predicate kastas en InvalidOperationException med meddelandet "Sequence innehåller inget matchande element".

Exempel

// Returns "a":
new[] { "a" }.Last();

// Returns "b":
new[] { "a", "b" }.Last();

// Returns "a":
new[] { "a", "b" }.Last(x => x.Equals("a"));

// Returns "be":
new[] { "ba", "be" }.Last(x => x.Contains("b"));

// Throws InvalidOperationException:
new[] { "ca", "ce" }.Last(x => x.Contains("b"));

// Throws InvalidOperationException:
new string[0].Last(); 

LastOrDefault ()

  • Returnerar det sista elementet i en sekvens eller det sista elementet som matchar det angivna predicate .
  • Om sekvensen inte innehåller några element, eller inga element som matchar det angivna predicate , returnerar standardvärdet för sekvenstypen med hjälp av default(T) .

Exempel

// Returns "a":
new[] { "a" }.LastOrDefault();

// Returns "b":
new[] { "a", "b" }.LastOrDefault();

// Returns "a":
new[] { "a", "b" }.LastOrDefault(x => x.Equals("a"));

 // Returns "be":
new[] { "ba", "be" }.LastOrDefault(x => x.Contains("b"));

// Returns null:
new[] { "ca", "ce" }.LastOrDefault(x => x.Contains("b")); 

// Returns null:
new string[0].LastOrDefault();

Enda()

  • Om sekvensen innehåller exakt ett element, eller exakt ett element som matchar det medgivna predicate , returneras det elementet.
  • Om sekvensen inte innehåller några element, eller inga element som matchar det angivna predicate , InvalidOperationException en InvalidOperationException med meddelandet "Sekvens innehåller inga element".
  • Om sekvensen innehåller mer än ett element, eller mer än ett element som matchar det angivna predicate , InvalidOperationException en InvalidOperationException med meddelandet "Sequence innehåller mer än ett element".
  • Obs: För att utvärdera om sekvensen innehåller exakt ett element måste högst två element räknas upp.

Exempel

// Returns "a":
new[] { "a" }.Single();

// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "b" }.Single();

// Returns "b":
new[] { "a", "b" }.Single(x => x.Equals("b"));

// Throws InvalidOperationException:
new[] { "a", "b" }.Single(x => x.Equals("c"));

// Throws InvalidOperationException:
new string[0].Single(); 

// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "a" }.Single();

SingleOrDefault ()

  • Om sekvensen innehåller exakt ett element, eller exakt ett element som matchar det medgivna predicate , returneras det elementet.
  • Om sekvensen inte innehåller några element, eller inga element som matchar det angivna predicate , returneras default(T) .
  • Om sekvensen innehåller mer än ett element, eller mer än ett element som matchar det angivna predicate , InvalidOperationException en InvalidOperationException med meddelandet "Sequence innehåller mer än ett element".
  • Om sekvensen inte innehåller några element som matchar det angivna predicate , returnerar du standardvärdet för sekvenstypen med hjälp av default(T) .
  • Obs: För att utvärdera om sekvensen innehåller exakt ett element måste högst två element räknas upp.

Exempel

// Returns "a":
new[] { "a" }.SingleOrDefault();

// returns "a"
new[] { "a", "b" }.SingleOrDefault(x => x == "a"); 

// Returns null:
new[] { "a", "b" }.SingleOrDefault(x => x == "c");

// Throws InvalidOperationException:
new[] { "a", "a" }.SingleOrDefault(x => x == "a");

// Throws InvalidOperationException:
new[] { "a", "b" }.SingleOrDefault();

// Returns null:
new string[0].SingleOrDefault();

rekommendationer

  • Även om du kan använda FirstOrDefault , LastOrDefault eller SingleOrDefault att kontrollera om en sekvens innehåller några objekt, är Any eller Count mer pålitliga. Detta beror på att ett returvärde för default(T) från en av dessa tre metoder inte bevisar att sekvensen är tom, eftersom värdet på det första / sista / enstaka elementet i sekvensen lika kan vara default(T)

  • Bestäm vilka metoder som passar din kod mest. Använd till exempel endast Single om du måste se till att det finns ett enda objekt i samlingen som matchar ditt predikat - använd annars First ; som Single ett undantag om sekvensen har mer än ett matchande element. Detta gäller naturligtvis även för "* OrDefault" -telefonerna.

  • Beträffande effektivitet: Även om det ofta är lämpligt att se till att det bara finns en artikel ( Single ) eller, antingen bara en eller noll ( SingleOrDefault ), som returneras av en fråga, kräver båda dessa metoder mer, och ofta hela, samlingen som ska undersökas för att säkerställa att det inte finns någon andra matchning till frågan. Detta är till skillnad från till exempel den First metoden, som kan vara nöjd efter att ha hittat den första matchen.

Bortsett från

Metoden Except returnerar uppsättningen objekt som finns i den första samlingen men som inte finns i den andra. Standard IEqualityComparer används för att jämföra objekten inom de två uppsättningarna. Det finns en överbelastning som accepterar en IEqualityComparer som ett argument.

Exempel:

int[] first = { 1, 2, 3, 4 };
int[] second = { 0, 2, 3, 5 };

IEnumerable<int> inFirstButNotInSecond = first.Except(second);
// inFirstButNotInSecond = { 1, 4 }

Produktion:

1
4

Live-demonstration på .NET Fiddle

I detta fall .Except(second) innehöll utesluter element i arrayen second , nämligen 2 och 3 (0 och 5 inte finns i den first uppsättningen och hoppas över).

Observera att Except innebär Distinct (dvs. det tar bort upprepade element). Till exempel:

int[] third = { 1, 1, 1, 2, 3, 4 };

IEnumerable<int> inThirdButNotInSecond = third.Except(second);
// inThirdButNotInSecond = { 1, 4 }

Produktion:

1
4

Live-demonstration på .NET Fiddle

I detta fall returneras elementen 1 och 4 endast en gång.


Implementering av IEquatable eller tillhandahållande av funktionen som en IEqualityComparer gör det möjligt att använda en annan metod för att jämföra elementen. Observera att GetHashCode metoden också bör åsidosättas så att den returnerar en identisk hashkod för object som är identiska enligt IEquatable implementeringen.

Exempel med IEquatable:

class Holiday : IEquatable<Holiday>
{
    public string Name { get; set; }

    public bool Equals(Holiday other)
    {
        return Name == other.Name;
    }

    // GetHashCode must return true whenever Equals returns true.
    public override int GetHashCode()
    {
        //Get hash code for the Name field if it is not null.
        return Name?.GetHashCode() ?? 0;
    }
}

public class Program
{
    public static void Main()
    {
        List<Holiday> holidayDifference = new List<Holiday>();

        List<Holiday> remoteHolidays = new List<Holiday>
        {
            new Holiday { Name = "Xmas" },
            new Holiday { Name = "Hanukkah" },
            new Holiday { Name = "Ramadan" }
        };

        List<Holiday> localHolidays = new List<Holiday>
        {
            new Holiday { Name = "Xmas" },
            new Holiday { Name = "Ramadan" }
        };

        holidayDifference = remoteHolidays
            .Except(localHolidays)
            .ToList();

        holidayDifference.ForEach(x => Console.WriteLine(x.Name));
    }
}

Produktion:

Hanukkah

Live-demonstration på .NET Fiddle

SelectMany: Flating en sekvens av sekvenser

var sequenceOfSequences = new [] { new [] { 1, 2, 3 }, new [] { 4, 5 }, new [] { 6 } };
var sequence = sequenceOfSequences.SelectMany(x => x);
// returns { 1, 2, 3, 4, 5, 6 }

Använd SelectMany() om du har, eller om du skapar en sekvenssekvens, men du vill ha resultatet som en lång sekvens.

I LINQ Query Syntax:

var sequence = from subSequence in sequenceOfSequences
               from item in subSequence
               select item;

Om du har en samling samlingar och vill kunna arbeta med data från föräldrar- och SelectMany samtidigt är det också möjligt med SelectMany .

Låt oss definiera enkla klasser

public class BlogPost
{
    public int Id { get; set; }
    public string Content { get; set; }
    public List<Comment> Comments { get; set; }
}

public class Comment
{
    public int Id { get; set; }
    public string Content { get; set; }
}

Låt oss anta att vi har följande samling.

List<BlogPost> posts = new List<BlogPost>()
{
    new BlogPost()
    {
        Id = 1,
        Comments = new List<Comment>()
        {
            new Comment()
            {
                Id = 1,
                Content = "It's really great!",
            },
            new Comment()
            {
                Id = 2,
                Content = "Cool post!"
            }
        }
    },
    new BlogPost()
    {
        Id = 2,
        Comments = new List<Comment>()
        {
            new Comment()
            {
                Id = 3,
                Content = "I don't think you're right",
            },
            new Comment()
            {
                Id = 4,
                Content = "This post is a complete nonsense"
            }
        }
    }
};

Nu vill vi välja kommentarer Content tillsammans med Id of BlogPost associerat med den här kommentaren. För att göra det kan vi använda lämplig SelectMany överbelastning.

var commentsWithIds = posts.SelectMany(p => p.Comments, (post, comment) => new { PostId = post.Id, CommentContent = comment.Content });

Våra commentsWithIds ser ut så här

{
    PostId = 1,
    CommentContent = "It's really great!"
},
{
    PostId = 1,
    CommentContent = "Cool post!"
},
{
    PostId = 2,
    CommentContent = "I don't think you're right"
},
{
    PostId = 2,
    CommentContent = "This post is a complete nonsense"
}

SelectMany

SelectMany linq-metoden 'plattar' en IEnumerable<IEnumerable<T>> till en IEnumerable<T> . Alla T-element i de IEnumerable instanserna som finns i källan IEnumerable kommer att kombineras till en enda IEnumerable .

var words = new [] { "a,b,c", "d,e", "f" };
var splitAndCombine = words.SelectMany(x => x.Split(','));
// returns { "a", "b", "c", "d", "e", "f" }

Om du använder en väljarfunktion som förvandlar inmatningselement till sekvenser blir resultatet elementen i de sekvenserna som returneras en efter en.

Observera att, till skillnad från Select() , antalet element i utgången inte behöver vara detsamma som i ingången.

Mer verkligt exempel

class School
{
    public Student[] Students { get; set; }
}

class Student 
{
    public string Name { get; set; }
}    
  
var schools = new [] {
    new School(){ Students = new [] { new Student { Name="Bob"}, new Student { Name="Jack"} }},
    new School(){ Students = new [] { new Student { Name="Jim"}, new Student { Name="John"} }}
};
               
var allStudents = schools.SelectMany(s=> s.Students);
             
foreach(var student in allStudents)
{
    Console.WriteLine(student.Name);
}

Produktion:

Guppa
domkraft
Jim
John

Live-demonstration på .NET Fiddle

Allt

All används för att kontrollera om alla element i en samling matchar ett villkor eller inte.
se också: .Alla

1. Tom parameter

Alla : får inte användas med en tom parameter.

2. Lambda-uttryck som parameter

Allt : Returnerar true om alla element i samlingen uppfyller lambdauttrycket och annars false :

var numbers = new List<int>(){ 1, 2, 3, 4, 5};
bool result = numbers.All(i => i < 10); // true
bool result = numbers.All(i => i >= 3); // false

3. Tom samling

Allt : Returnerar true om samlingen är tom och ett lambda-uttryck levereras:

var numbers = new List<int>();
bool result = numbers.All(i => i >= 0); // true

Obs: All kommer att stoppa iterationen av samlingen så snart den hittar ett element som inte matchar villkoret. Detta innebär att samlingen inte nödvändigtvis kommer att räknas upp helt; det kommer bara att räknas tillräckligt långt för att hitta den första artikeln som inte matchar villkoret.

Frågesamling efter typ / cast-element att skriva

interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }

var item0 = new Foo();
var item1 = new Foo();
var item2 = new Bar();
var item3 = new Bar();
var collection = new IFoo[] { item0, item1, item2, item3 };

Använda OfType

var foos = collection.OfType<Foo>(); // result: IEnumerable<Foo> with item0 and item1
var bars = collection.OfType<Bar>(); // result: IEnumerable<Bar> item item2 and item3
var foosAndBars = collection.OfType<IFoo>(); // result: IEnumerable<IFoo> with all four items

Använda Where

var foos = collection.Where(item => item is Foo); // result: IEnumerable<IFoo> with item0 and item1
var bars = collection.Where(item => item is Bar); // result: IEnumerable<IFoo> with item2 and item3

Använda Cast

var bars = collection.Cast<Bar>();                // throws InvalidCastException on the 1st item
var foos = collection.Cast<Foo>();                // throws InvalidCastException on the 3rd item
var foosAndBars = collection.Cast<IFoo>();        // OK 

Union

Sammanfogar två samlingar för att skapa en distinkt samling med standardjämförelsekjämföraren

int[] numbers1 = { 1, 2, 3 };
int[] numbers2 = { 2, 3, 4, 5 };

var allElement = numbers1.Union(numbers2);   // AllElement now contains 1,2,3,4,5

Live-demonstration på .NET Fiddle

ANSLUTER SIG

Joins används för att kombinera olika listor eller tabeller som innehåller data via en gemensam nyckel.

Liksom i SQL stöds följande typer av Joins i LINQ:
Inre, vänster, höger, tvärgående och fullständiga yttre förbindelser.

Följande två listor används i exemplen nedan:

var first = new List<string>(){ "a","b","c"}; // Left data
var second = new List<string>(){ "a", "c", "d"}; // Right data

(Inre koppling

var result = from f in first
             join s in second on f equals s
             select new { f, s };

var result = first.Join(second, 
                        f => f, 
                        s => s,
                        (f, s) => new { f, s });

// Result: {"a","a"}
//         {"c","c"}

Vänster yttre sammanfogning

var leftOuterJoin = from f in first
                    join s in second on f equals s into temp
                    from t in temp.DefaultIfEmpty()
                    select new { First = f, Second = t};

// Or can also do:
var leftOuterJoin = from f in first
                    from s in second.Where(x => x == f).DefaultIfEmpty()
                    select new { First = f, Second = s};

// Result: {"a","a"}
//         {"b", null}  
//         {"c","c"}  


// Left outer join method syntax
var leftOuterJoinFluentSyntax = first.GroupJoin(second,
                                      f => f,
                                      s => s,
                                      (f, s) => new { First = f, Second = s })
                                   .SelectMany(temp => temp.Second.DefaultIfEmpty(),
                                      (f, s) => new { First = f.First, Second = s });

Right Yuter Join

var rightOuterJoin = from s in second
                     join f in first on s equals f into temp
                     from t in temp.DefaultIfEmpty()
                     select new {First=t,Second=s};

// Result: {"a","a"}
//         {"c","c"}  
//         {null,"d"}  

Cross Join

var CrossJoin = from f in first
                from s in second
                select new { f, s };

// Result: {"a","a"}
//         {"a","c"}  
//         {"a","d"}  
//         {"b","a"}
//         {"b","c"}  
//         {"b","d"}  
//         {"c","a"}
//         {"c","c"}  
//         {"c","d"}

Full Yuter Join

var fullOuterjoin = leftOuterJoin.Union(rightOuterJoin);

// Result: {"a","a"}
//         {"b", null}  
//         {"c","c"}  
//         {null,"d"}

Praktiskt exempel

Exemplen ovan har en enkel datastruktur så att du kan fokusera på att förstå de olika LINQ-kopplingarna tekniskt, men i den verkliga världen skulle du ha tabeller med kolumner som du behöver gå med i.

I följande exempel finns det bara en klass Region används i verkligheten skulle du sammanfoga två eller flera olika tabeller som håller samma nyckel (i detta exempel first och second är förenade via den gemensamma nyckeln ID ).

Exempel: Tänk på följande datastruktur:

public class Region 
{
    public Int32 ID;
    public string RegionDescription;
    
    public Region(Int32 pRegionID, string pRegionDescription=null)
    {
        ID = pRegionID; RegionDescription = pRegionDescription;
    }
}

Förbered nu data (dvs. fyll i data):

// Left data
var first = new List<Region>() 
                 { new Region(1), new Region(3), new Region(4) }; 
// Right data
var second = new List<Region>() 
                 { 
                    new Region(1, "Eastern"),  new Region(2, "Western"),
                    new Region(3, "Northern"), new Region(4, "Southern")
                 }; 

Du kan se att i det här exemplet first inte innehåller några regionbeskrivningar så att du vill gå med dem från second . Då skulle den inre kopplingen se ut:

// do the inner join
var result = from f in first
             join s in second on f.ID equals s.ID
             select new { f.ID, s.RegionDescription };


 // Result: {1,"Eastern"}
 //         {3, Northern}  
 //         {4,"Southern"}  

Detta resultat har skapat anonyma objekt i farten, vilket är bra, men vi har redan skapat en ordentlig klass - så vi kan ange det: Istället för att select new { f.ID, s.RegionDescription }; vi kan säga select new Region(f.ID, s.RegionDescription); , som kommer att returnera samma data men skapar objekt av typ Region - som kommer att upprätthålla kompatibilitet med de andra objekten.

Live-demo på .NET-fiol

Distinkt

Returnerar unika värden från ett IEnumerable . Unikhet bestäms med hjälp av jämställdhetsjämföraren.

int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };

var distinct = array.Distinct();
// distinct = { 1, 2, 3, 4, 5 }

För att jämföra en anpassad datatyp måste vi implementera IEquatable<T> -gränssnittet och tillhandahålla GetHashCode och Equals metoder för typen. Eller jämställdhetsjämföraren kan åsidosättas:

class SSNEqualityComparer : IEqualityComparer<Person> {
    public bool Equals(Person a, Person b) => return a.SSN == b.SSN;
    public int GetHashCode(Person p) => p.SSN;
}

List<Person> people;

distinct = people.Distinct(SSNEqualityComparer);

GroupBy ett eller flera fält

Låt oss anta att vi har någon filmmodell:

public class Film {
    public string Title { get; set; }
    public string Category { get; set; }
    public int Year { get; set; }
}

Grupp efter kategori egendom:

foreach (var grp in films.GroupBy(f => f.Category)) {
    var groupCategory = grp.Key;
    var numberOfFilmsInCategory = grp.Count();
}

Grupp efter kategori och år:

foreach (var grp in films.GroupBy(f => new { Category = f.Category, Year = f.Year })) {
    var groupCategory = grp.Key.Category;
    var groupYear = grp.Key.Year;
    var numberOfFilmsInCategory = grp.Count();
}

Använd Range med olika Linq-metoder

Du kan använda klassen Enumerable tillsammans med Linqfrågor för att konvertera för slingor till Linq one-foder.

Välj exempel

Motsatt sig att göra detta:

var asciiCharacters = new List<char>();
for (var x = 0; x < 256; x++)
{
    asciiCharacters.Add((char)x);
}

Du kan göra det här:

var asciiCharacters = Enumerable.Range(0, 256).Select(a => (char) a);

Där exempel

I det här exemplet kommer 100 nummer att genereras och även de extraheras

var evenNumbers = Enumerable.Range(1, 100).Where(a => a % 2 == 0);

Frågeställning - OrderBy () ThenBy () OrderByDescending () ThenByDescending ()

string[] names= { "mark", "steve", "adam" };

Stigande:

Frågesyntax

var sortedNames =
    from name in names
    orderby name
    select name;

Metodsyntax

var sortedNames = names.OrderBy(name => name);

sortedNames innehåller namnen i följande ordning: "adam", "mark", "steve"

Nedåtgående:

Frågesyntax

var sortedNames =
    from name in names
    orderby name descending
    select name;

Metodsyntax

var sortedNames = names.OrderByDescending(name => name);

sortedNames innehåller namnen i följande ordning: "steve", "mark", "adam"

Beställ efter flera fält

Person[] people =
{
    new Person { FirstName = "Steve", LastName = "Collins", Age = 30},
    new Person { FirstName = "Phil" , LastName = "Collins", Age = 28},
    new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 29},
    new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 15}
};

Frågesyntax

var sortedPeople = from person in people
                   orderby person.LastName, person.FirstName, person.Age descending
                   select person;

Metodsyntax

 sortedPeople = people.OrderBy(person => person.LastName)
                      .ThenBy(person => person.FirstName)
                      .ThenByDescending(person => person.Age);

Resultat

1. Adam Ackerman 29
2. Adam Ackerman 15
3. Phil Collins  28
4. Steve Collins 30

Grunderna

LINQ är till stor del fördelaktigt för frågesamlingar (eller matriser).

Med t ex följande provdata:

var classroom = new Classroom
{
    new Student { Name = "Alice", Grade = 97, HasSnack = true  },
    new Student { Name = "Bob",   Grade = 82, HasSnack = false },
    new Student { Name = "Jimmy", Grade = 71, HasSnack = true  },
    new Student { Name = "Greg",  Grade = 90, HasSnack = false },
    new Student { Name = "Joe",   Grade = 59, HasSnack = false }
}

Vi kan "fråga" om dessa data med LINQ-syntax. Till exempel för att hämta alla studenter som har ett mellanmål idag:

var studentsWithSnacks = from s in classroom.Students
                         where s.HasSnack
                         select s;

Eller, för att hämta elever med en grad av 90 eller högre och bara returnera deras namn, inte hela Student :

var topStudentNames = from s in classroom.Students
                      where s.Grade >= 90
                      select s.Name;

LINQ-funktionen består av två syntaxer som utför samma funktioner, har nästan identiska prestanda, men skrivs väldigt annorlunda. Syntaxen i exemplet ovan kallas frågsyntax . Följande exempel illustrerar dock metatsyntax . Samma data kommer att returneras som i exemplet ovan, men hur frågan skrivs är annorlunda.

var topStudentNames = classroom.Students
                               .Where(s => s.Grade >= 90)
                               .Select(s => s.Name);

Grupp av

GroupBy är ett enkelt sätt att sortera en IEnumerable<T> samling av objekt i olika grupper.

Enkelt exempel

I detta första exempel slutar vi med två grupper, udda och jämna objekt.

List<int> iList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var grouped = iList.GroupBy(x => x % 2 == 0);

//Groups iList into odd [13579] and even[2468] items 
       
foreach(var group in grouped)
{
    foreach (int item in group)
    {
        Console.Write(item); // 135792468  (first odd then even)
    }
}

Mer komplext exempel

Låt oss ta ett exempel på gruppering av en lista över personer efter ålder. Först skapar vi ett Personobjekt som har två egenskaper, Namn och Ålder.

public class Person
{
    public int Age {get; set;}
    public string Name {get; set;}
}

Sedan skapar vi vår lista med personer med olika namn och åldrar.

List<Person> people = new List<Person>();
people.Add(new Person{Age = 20, Name = "Mouse"});
people.Add(new Person{Age = 30, Name = "Neo"});
people.Add(new Person{Age = 40, Name = "Morpheus"});
people.Add(new Person{Age = 30, Name = "Trinity"});
people.Add(new Person{Age = 40, Name = "Dozer"});
people.Add(new Person{Age = 40, Name = "Smith"});

Sedan skapar vi en LINQ-fråga för att gruppera vår lista över personer efter ålder.

var query = people.GroupBy(x => x.Age);

Genom att göra det kan vi se åldern för varje grupp och ha en lista över varje person i gruppen.

foreach(var result in query)
{
    Console.WriteLine(result.Key);
                
    foreach(var person in result)
        Console.WriteLine(person.Name);
}

Detta resulterar i följande utgång:

20
Mouse
30
Neo
Trinity
40
Morpheus
Dozer
Smith

Du kan spela med live-demonstrationen på. NET Fiddle

Några

Any används för att kontrollera om något element i en samling matchar ett villkor eller inte.
se också: .All , Any och FirstOrDefault: bästa praxis

1. Tom parameter

Any : Returnerar true om samlingen har några element och false om samlingen är tom:

var numbers = new List<int>();
bool result = numbers.Any(); // false

var numbers = new List<int>(){ 1, 2, 3, 4, 5};
bool result = numbers.Any(); //true

2. Lambda-uttryck som parameter

Any : Returnerar true om samlingen har ett eller flera element som uppfyller villkoret i lambda-uttrycket:

var arrayOfStrings = new string[] { "a", "b", "c" };
arrayOfStrings.Any(item => item == "a");    // true
arrayOfStrings.Any(item => item == "d");    // false

3. Tom samling

Any : Returnerar false om samlingen är tom och ett lambda-uttryck levereras:

var numbers = new List<int>();
bool result = numbers.Any(i => i >= 0); // false

Obs: Any kommer att stoppa iterationen av samlingen så snart den hittar ett element som matchar villkoret. Detta innebär att samlingen inte nödvändigtvis kommer att räknas upp helt; det kommer bara att räknas tillräckligt långt för att hitta den första artikeln som matchar villkoret.

Live-demonstration på .NET Fiddle

ToDictionary

LINQ-metoden ToDictionary() kan användas för att generera en Dictionary<TKey, TElement> baserad på en given IEnumerable<T> .

IEnumerable<User> users = GetUsers();
Dictionary<int, User> usersById = users.ToDictionary(x => x.Id);

I det här exemplet är det enda argumentet som skickas till ToDictionary av typen Func<TSource, TKey> , som returnerar nyckeln för varje element.

Detta är ett kortfattat sätt att utföra följande operation:

Dictionary<int, User> usersById = new Dictionary<int User>();
foreach (User u in users) 
{
  usersById.Add(u.Id, u);
}

Du kan också skicka en andra parameter till ToDictionary metoden, som är av typen Func<TSource, TElement> och returnerar Value som ska läggas till för varje post.

IEnumerable<User> users = GetUsers();
Dictionary<int, string> userNamesById = users.ToDictionary(x => x.Id, x => x.Name);

Det är också möjligt att specificera IComparer som används för att jämföra nyckelvärden. Detta kan vara användbart när nyckeln är en sträng och du vill att den ska matcha bristande känslig.

IEnumerable<User> users = GetUsers();
Dictionary<string, User> usersByCaseInsenstiveName = users.ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase);

var user1 = usersByCaseInsenstiveName["john"];
var user2 = usersByCaseInsenstiveName["JOHN"];
user1 == user2; // Returns true

Obs: ToDictionary metoden kräver att alla nycklar är unika, det får inte finnas duplikatnycklar. Om det finns, kastas ett undantag: ArgumentException: An item with the same key has already been added. Om du har ett scenario där du vet att du kommer att ha flera element med samma nyckel är du bättre att använda ToLookup istället.

Aggregate

Aggregate Tillämpar en ackumulatorfunktion över en sekvens.

int[] intList = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = intList.Aggregate((prevSum, current) => prevSum + current);
// sum = 55
  • Vid det första steget prevSum = 1
  • Vid det andra prevSum = prevSum(at the first step) + 2
  • Vid det i-de steget prevSum = prevSum(at the (i-1) step) + i-th element of the array
string[] stringList = { "Hello", "World", "!" };
string joinedString = stringList.Aggregate((prev, current) => prev + " " + current);
// joinedString = "Hello World !"

En andra överbelastning av Aggregate mottar även en seed parameter, som är den initiala ackumulatorvärdet. Detta kan användas för att beräkna flera villkor på en samling utan att upprepa det mer än en gång.

List<int> items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

För insamlingen av items vi vill beräkna

  1. Den totala .Count
  2. Mängden jämna siffror
  3. Samla varje framåt

Med hjälp av Aggregate kan det göras så här:

var result = items.Aggregate(new { Total = 0, Even = 0, FourthItems = new List<int>() },
                (accumelative,item) =>
                new {
                    Total = accumelative.Total + 1,
                    Even = accumelative.Even + (item % 2 == 0 ? 1 : 0),
                    FourthItems = (accumelative.Total + 1)%4 == 0 ? 
                        new List<int>(accumelative.FourthItems) { item } : 
                        accumelative.FourthItems 
                });
// Result:
// Total = 12
// Even = 6
// FourthItems = [4, 8, 12]

Observera att om man använder en anonym typ som frö måste man instansera ett nytt objekt för varje objekt eftersom egenskaperna endast är läsade. Med hjälp av en anpassad klass kan man helt enkelt tilldela uppgifter och ingen new behövs (endast i samband med den första seed parametern

Definiera en variabel i en Linq-fråga (låt nyckelord)

För att definiera en variabel i en LINQ uttryck kan du använda Let sökord. Detta görs vanligtvis för att lagra resultaten från mellanliggande undersökningar, till exempel:

 int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

 var aboveAverages = from number in numbers
                     let average = numbers.Average()
                     let nSquared = Math.Pow(number,2)
                     where nSquared > average
                     select number;

 Console.WriteLine("The average of the numbers is {0}.", numbers.Average());

 foreach (int n in aboveAverages)
 {
   Console.WriteLine("Query result includes number {0} with square of {1}.", n, Math.Pow(n,2));
 }

Produktion:

Genomsnittet av siffrorna är 4,5.
Frågoresultatet inkluderar nummer 3 med kvadrat 9.
Frågoresultatet inkluderar nummer 4 med kvadrat på 16.
Frågoresultatet inkluderar nummer 5 med kvadrat på 25.
Frågoresultatet inkluderar nummer 6 med kvadrat 36.
Frågoresultatet inkluderar nummer 7 med kvadrat på 49.
Frågoresultatet inkluderar nummer 8 med kvadratet 64.
Frågoresultatet inkluderar nummer 9 med kvadrat 81.

Visa demo

SkipWhile

SkipWhile() används för att utesluta element till första matchningen (detta kan vara mot intuitivt för de flesta)

int[] list = { 42, 42, 6, 6, 6, 42 };
var result = list.SkipWhile(i => i == 42); 
// Result: 6, 6, 6, 42

DefaultIfEmpty

StandardIfEmpty används för att returnera ett standardelement om sekvensen inte innehåller några element. Detta element kan vara standard för typen eller en användardefinierad instans av den typen. Exempel:

var chars = new List<string>() { "a", "b", "c", "d" };

chars.DefaultIfEmpty("N/A").FirstOrDefault(); // returns "a";

chars.Where(str => str.Length > 1)
     .DefaultIfEmpty("N/A").FirstOrDefault(); // return "N/A"

chars.Where(str => str.Length > 1)
        .DefaultIfEmpty().First(); // returns null;

Användning i vänsterfogar :

Med DefaultIfEmpty det traditionella Linq Join returnera ett standardobjekt om ingen matchning hittades. Således fungerar som en SQL: s vänstra anslutning. Exempel:

var leftSequence = new List<int>() { 99, 100, 5, 20, 102, 105 };
var rightSequence = new List<char>() { 'a', 'b', 'c', 'i', 'd' };

var numbersAsChars = from l in leftSequence
                     join r in rightSequence
                     on l equals (int)r into leftJoin
                     from result in leftJoin.DefaultIfEmpty('?')
                     select new
                     {
                         Number = l,
                         Character = result
                     };

foreach(var item in numbersAsChars)
{
    Console.WriteLine("Num = {0} ** Char = {1}", item.Number, item.Character);
}

ouput: 

Num = 99         Char = c
Num = 100        Char = d
Num = 5          Char = ?
Num = 20         Char = ?
Num = 102        Char = ?
Num = 105        Char = i

I fallet där en DefaultIfEmpty används (utan att ange ett standardvärde) och det kommer att resultera kommer inga matchande objekt i rätt sekvens att vara säker på att objektet inte är null innan du får tillgång till dess egenskaper. Annars kommer det att resultera i en NullReferenceException . Exempel:

var leftSequence = new List<int> { 1, 2, 5 };
var rightSequence = new List<dynamic>()
    {
        new { Value = 1 },
        new { Value = 2 },
        new { Value = 3 },
        new { Value = 4 },
    };

var numbersAsChars = (from l in leftSequence
                        join r in rightSequence
                        on l equals r.Value into leftJoin
                        from result in leftJoin.DefaultIfEmpty()
                        select new
                        {
                            Left = l,
                            // 5 will not have a matching object in the right so result 
                            // will be equal to null. 
                            // To avoid an error use:
                            //    -  C# 6.0 or above - ?. 
                            //    -  Under           - result == null ? 0 : result.Value
                            Right = result?.Value
                        }).ToList();

SequenceEqual

SequenceEqual används för att jämföra två IEnumerable<T> -sekvenser med varandra.

int[] a = new int[] {1, 2, 3};
int[] b = new int[] {1, 2, 3};
int[] c = new int[] {1, 3, 2};

bool returnsTrue = a.SequenceEqual(b);
bool returnsFalse = a.SequenceEqual(c);

Räkna och LongCount

Count ger antalet element i en IEnumerable<T> . Count visar även en valfri predikatparameter som låter dig filtrera de element du vill räkna.

int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };

int n = array.Count(); // returns the number of elements in the array
int x = array.Count(i => i > 2); // returns the number of elements in the array greater than 2

LongCount fungerar på samma sätt som Count men har en returtyp av long och används för att räkna IEnumerable<T> sekvenser som är längre än int.MaxValue

int[] array = GetLargeArray();

long n = array.LongCount(); // returns the number of elements in the array
long x = array.LongCount(i => i > 100); // returns the number of elements in the array greater than 100

Bygga en fråga stegvis

Eftersom LINQ använder uppskjuten exekvering kan vi ha ett frågaobjekt som inte faktiskt innehåller värdena, men kommer att returnera värdena när de utvärderas. Vi kan således dynamiskt bygga frågan baserat på vårt kontrollflöde och utvärdera den när vi är klar:

IEnumerable<VehicleModel> BuildQuery(int vehicleType, SearchModel search, int start = 1, int count = -1) {
    IEnumerable<VehicleModel> query = _entities.Vehicles
        .Where(x => x.Active && x.Type == vehicleType)
        .Select(x => new VehicleModel {
            Id = v.Id,
            Year = v.Year,
            Class = v.Class,
            Make = v.Make,
            Model = v.Model,
            Cylinders = v.Cylinders ?? 0
        });

Vi kan villkorat tillämpa filter:

    if (!search.Years.Contains("all", StringComparer.OrdinalIgnoreCase))
        query = query.Where(v => search.Years.Contains(v.Year));

    if (!search.Makes.Contains("all", StringComparer.OrdinalIgnoreCase)) {
        query = query.Where(v => search.Makes.Contains(v.Make));
    }

    if (!search.Models.Contains("all", StringComparer.OrdinalIgnoreCase)) {
        query = query.Where(v => search.Models.Contains(v.Model));
    }

    if (!search.Cylinders.Equals("all", StringComparer.OrdinalIgnoreCase)) {
        decimal minCylinders = 0;
        decimal maxCylinders = 0;
        switch (search.Cylinders) {
            case "2-4":
                maxCylinders = 4;
                break;
            case "5-6":
                minCylinders = 5;
                maxCylinders = 6;
                break;
            case "8":
                minCylinders = 8;
                maxCylinders = 8;
                break;
            case "10+":
                minCylinders = 10;
                break;
        }
        if (minCylinders > 0) {
            query = query.Where(v => v.Cylinders >= minCylinders);
        }
        if (maxCylinders > 0) {
            query = query.Where(v => v.Cylinders <= maxCylinders);
        }
    }

Vi kan lägga till en sorteringsordning i frågan baserat på ett villkor:

    switch (search.SortingColumn.ToLower()) {
        case "make_model":
            query = query.OrderBy(v => v.Make).ThenBy(v => v.Model);
            break;
        case "year":
            query = query.OrderBy(v => v.Year);
            break;
        case "engine_size":
            query = query.OrderBy(v => v.EngineSize).ThenBy(v => v.Cylinders);
            break;
        default:
            query = query.OrderBy(v => v.Year); //The default sorting.
    }

Vår fråga kan definieras så att den startar från en given punkt:

    query = query.Skip(start - 1);

och definierat för att returnera ett specifikt antal poster:

    if (count > -1) {
        query = query.Take(count);
    }
    return query;
}

När vi har frågaobjektet kan vi utvärdera resultaten med en foreach eller en av LINQ-metoderna som returnerar en uppsättning värden, till exempel ToList eller ToArray :

SearchModel sm;

// populate the search model here
// ...

List<VehicleModel> list = BuildQuery(5, sm).ToList();

Blixtlås

Zip förlängningsmetoden verkar på två samlingar. Det parar varje element i de två serierna tillsammans baserat på position. Med en Func instans använder vi Zip att hantera element från de två C # -samlingarna i par. Om serierna skiljer sig åt i storlek ignoreras de extra elementen i den större serien.

För att ta ett exempel från boken "C # i ett nötskal",

int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip(words, (n, w) => n + "=" + w);

Produktion:

3 = tre
5 = fem
7 = sju

Visa demo

GroupJoin med variabel för yttre räckvidd

Customer[] customers = Customers.ToArray();
Purchase[] purchases = Purchases.ToArray();

var groupJoinQuery =
    from c in customers
    join p in purchases on c.ID equals p.CustomerID
    into custPurchases
    select new
    {
        CustName = c.Name,
        custPurchases
    };

ElementAt och ElementAtOrDefault

ElementAt returnerar artikeln vid index n . Om n inte ligger inom det antal som räknas, kastar du en ArgumentOutOfRangeException .

int[] numbers  = { 1, 2, 3, 4, 5 };
numbers.ElementAt(2);  // 3
numbers.ElementAt(10); // throws ArgumentOutOfRangeException

ElementAtOrDefault returnerar artikeln vid index n . Om n inte ligger inom det antal som räknas, returnerar du ett default(T) .

int[] numbers  = { 1, 2, 3, 4, 5 };
numbers.ElementAtOrDefault(2);  // 3
numbers.ElementAtOrDefault(10); // 0 = default(int)

Både ElementAt och ElementAtOrDefault är optimerade för när källan är en IList<T> och normal indexering kommer att användas i dessa fall.

Observera att för ElementAt , om det angivna indexet är större än storleken på IList<T> , bör listan (men är tekniskt inte garanterad) kasta ett ArgumentOutOfRangeException .

Linq kvantifierare

Kvantifieringsoperationer returnerar ett booleskt värde om vissa eller alla elementen i en sekvens uppfyller ett villkor. I den här artikeln kommer vi att se några vanliga LINQ till Objekt-scenarier där vi kan använda dessa operatörer. Det finns 3 kvantifierare-operationer som kan användas i LINQ:

All - används för att bestämma om alla element i en sekvens uppfyller ett villkor. T.ex:

int[] array = { 10, 20, 30 }; 
   
// Are all elements >= 10? YES
array.All(element => element >= 10); 
   
// Are all elements >= 20? NO
array.All(element => element >= 20);
    
// Are all elements < 40? YES
array.All(element => element < 40);

Any - används för att bestämma om några element i en sekvens uppfyller ett villkor. T.ex:

int[] query=new int[] { 2, 3, 4 }
query.Any (n => n == 3);

Contains - används för att bestämma om en sekvens innehåller ett specificerat element. T.ex:

//for int array
int[] query =new int[] { 1,2,3 };
query.Contains(1);

//for string array
string[] query={"Tom","grey"};
query.Contains("Tom");

//for a string
var stringValue="hello";
stringValue.Contains("h");

Gå med i flera sekvenser

Betrakta enheter Customer , Purchase och PurchaseItem enligt följande:

public class Customer
{
   public string Id { get; set } // A unique Id that identifies customer    
   public string Name  {get; set; }
}

public class Purchase
{
   public string Id { get; set }
   public string CustomerId {get; set; }
   public string Description { get; set; }
}

public class PurchaseItem
{
   public string Id { get; set }
   public string PurchaseId {get; set; }
   public string Detail { get; set; }
}

Överväg att följa exempeldata för ovanstående enheter:

var customers = new List<Customer>()             
 {
    new Customer() {
        Id = Guid.NewGuid().ToString(),
        Name = "Customer1"            
    },
            
    new Customer() {
        Id = Guid.NewGuid().ToString(),
        Name = "Customer2"            
    }
 };        
    
 var purchases = new List<Purchase>() 
 {
     new Purchase() {                
         Id = Guid.NewGuid().ToString(),
         CustomerId = customers[0].Id,
         Description = "Customer1-Purchase1"            
     },

     new Purchase() {
         Id = Guid.NewGuid().ToString(),
         CustomerId = customers[0].Id,
         Description = "Customer1-Purchase2"            
     },
     
     new Purchase() {
         Id = Guid.NewGuid().ToString(),
         CustomerId = customers[1].Id,
         Description = "Customer2-Purchase1"            
     },

     new Purchase() {
         Id = Guid.NewGuid().ToString(),
         CustomerId = customers[1].Id,
         Description = "Customer2-Purchase2"            
     }
  };
    
 var purchaseItems = new List<PurchaseItem>() 
 {
     new PurchaseItem() {                
         Id = Guid.NewGuid().ToString(),
         PurchaseId= purchases[0].Id,
         Detail = "Purchase1-PurchaseItem1"            
     },

     new PurchaseItem() {                
         Id = Guid.NewGuid().ToString(),
         PurchaseId= purchases[1].Id,
         Detail = "Purchase2-PurchaseItem1"            
     },
     
     new PurchaseItem() {                
         Id = Guid.NewGuid().ToString(),
         PurchaseId= purchases[1].Id,
         Detail = "Purchase2-PurchaseItem2"            
     },

     new PurchaseItem() {                
         Id = Guid.NewGuid().ToString(),
         PurchaseId= purchases[3].Id,
         Detail = "Purchase3-PurchaseItem1"
     }
 };

Tänk nu under linqfrågan:

var result = from c in customers
            join p in purchases on c.Id equals p.CustomerId           // first join
            join pi in purchaseItems on p.Id equals pi.PurchaseId     // second join
            select new
            {
               c.Name, p.Description, pi.Detail
            };

För att mata ut resultatet av frågan ovan:

foreach(var resultItem in result)
{
    Console.WriteLine($"{resultItem.Name}, {resultItem.Description}, {resultItem.Detail}");
}

Utfrågan från frågan skulle vara:

Kund1, Kund1-Köp1, Köp1-KöpItem1

Kund1, Kund1-Köp2, Köp2-KöpItem1

Kund1, Kund1-Köp2, Köp2-KöpItem2

Kund2, Kund2-Köp2, Köp3-KöpItem1

Live-demonstration på .NET Fiddle

Gå med på flera tangenter

  PropertyInfo[] stringProps = typeof (string).GetProperties();//string properties
  PropertyInfo[] builderProps = typeof(StringBuilder).GetProperties();//stringbuilder properties
    
    var query =
        from s in stringProps
        join b in builderProps
            on new { s.Name, s.PropertyType } equals new { b.Name, b.PropertyType }
        select new
        {
            s.Name,
            s.PropertyType,
            StringToken = s.MetadataToken,
            StringBuilderToken = b.MetadataToken
        };

Observera att anonyma typer ovan join måste innehålla samma egenskaper eftersom objekt endast betraktas som lika om alla deras egenskaper är lika. Annars kommer frågan inte att kompilera.

Välj med Func selector - Använd för att få rankning av element

På överbelastningarna för utvidgningsmetoderna Select också index för det aktuella objektet i den samling som select . Det här är några användningsområden för det.

Få "radnumret" för objekten

var rowNumbers = collection.OrderBy(item => item.Property1)
                           .ThenBy(item => item.Property2)
                           .ThenByDescending(item => item.Property3)
                           .Select((item, index) => new { Item = item, RowNumber = index })
                           .ToList();

Få rankningen för ett objekt inom sin grupp

var rankInGroup = collection.GroupBy(item => item.Property1)
                            .OrderBy(group => group.Key)
                            .SelectMany(group => group.OrderBy(item => item.Property2)
                                                   .ThenByDescending(item => item.Property3)
                                                   .Select((item, index) => new 
                                                   { 
                                                       Item = item, 
                                                       RankInGroup = index 
                                                   })).ToList();

Få rankning av grupper (även känd i Oracle som dense_rank)

var rankOfBelongingGroup = collection.GroupBy(item => item.Property1)
                            .OrderBy(group => group.Key)
                            .Select((group, index) => new
                            {
                                Items = group,
                                Rank = index
                            })
                            .SelectMany(v => v.Items, (s, i) => new
                            {
                                Item = i,
                                DenseRank = s.Rank
                            }).ToList();

För att testa detta kan du använda:

public class SomeObject
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
    public int Property3 { get; set; }

    public override string ToString()
    {
        return string.Join(", ", Property1, Property2, Property3);
    }
}

Och data:

List<SomeObject> collection = new List<SomeObject>
{
    new SomeObject { Property1 = 1, Property2 = 1, Property3 = 1},
    new SomeObject { Property1 = 1, Property2 = 2, Property3 = 1},
    new SomeObject { Property1 = 1, Property2 = 2, Property3 = 2},
    new SomeObject { Property1 = 2, Property2 = 1, Property3 = 1},
    new SomeObject { Property1 = 2, Property2 = 2, Property3 = 1},
    new SomeObject { Property1 = 2, Property2 = 2, Property3 = 1},
    new SomeObject { Property1 = 2, Property2 = 3, Property3 = 1}
};

TakeWhile

TakeWhile returnerar element från en sekvens så länge villkoret är sant

int[] list = { 1, 10, 40, 50, 44, 70, 4 };
var result = list.TakeWhile(item => item < 50).ToList();
// result = { 1, 10, 40 }

Summa

Enumerable.Sum förlängning beräknar summan av numeriska värden.

Om samlingens element är själva siffror kan du beräkna summan direkt.

int[] numbers = new int[] { 1, 4, 6 };
Console.WriteLine( numbers.Sum() ); //outputs 11

Om typen av element är en komplex typ kan du använda ett lambda-uttryck för att ange det värde som ska beräknas:

var totalMonthlySalary = employees.Sum( employee => employee.MonthlySalary );

Summa-förlängningsmetoden kan beräkna med följande typer:

  • Int32
  • Int64
  • Enda
  • Dubbel
  • Decimal

Om din samling innehåller nollbara typer kan du använda operatören null-coalescing för att ställa in ett standardvärde för nullelement:

int?[] numbers = new int?[] { 1, null, 6 };
Console.WriteLine( numbers.Sum( number => number ?? 0 ) ); //outputs 7

Att kolla upp

ToLookup returnerar en datastruktur som tillåter indexering. Det är en förlängningsmetod. Den producerar en ILookup-instans som kan indexeras eller räknas upp med en förhandslinga. Posterna kombineras i grupperingar vid varje tangent. - dotnetperls

string[] array = { "one", "two", "three" };
//create lookup using string length as key
var lookup = array.ToLookup(item => item.Length);

//join the values whose lengths are 3
Console.WriteLine(string.Join(",",lookup[3]));
//output: one,two

Ett annat exempel:

int[] array = { 1,2,3,4,5,6,7,8 };
//generate lookup for odd even numbers (keys will be 0 and 1)
var lookup = array.ToLookup(item => item % 2);

//print even numbers after joining
Console.WriteLine(string.Join(",",lookup[0]));
//output: 2,4,6,8

//print odd numbers after joining
Console.WriteLine(string.Join(",",lookup[1]));
//output: 1,3,5,7

Bygg dina egna Linq-operatörer för IEnumerable

En av de fantastiska sakerna med Linq är att det är så enkelt att utöka. Du behöver bara skapa en förlängningsmetod vars argument är IEnumerable<T> .

public namespace MyNamespace
{
    public static class LinqExtensions
    {
        public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
        {
            var batch = new List<T>();
            foreach (T item in source)
            {
                batch.Add(item);
                if (batch.Count == batchSize)
                {
                    yield return batch;
                    batch = new List<T>();
                }
            }
            if (batch.Count > 0)
                yield return batch;
        }
    }
}

Det här exemplet delar upp objekten i ett IEnumerable<T> i listor med en fast storlek, den sista listan innehåller resten av objekten. Observera hur objektet som förlängningsmetoden tillämpas ledes i (argument source ) som den initiala argumentet med hjälp av this sökordet. Då yield nyckelordet används för att mata nästa objekt i den utgående IEnumerable<T> innan du fortsätter med utförandet från den punkten (se avkastnings sökord ).

Det här exemplet skulle användas i din kod så här:

//using MyNamespace;
var items = new List<int> { 2, 3, 4, 5, 6 };
foreach (List<int> sublist in items.Batch(3))
{
    // do something
}

På den första slingan skulle sublisten vara {2, 3, 4} och på den andra {5, 6} .

Anpassade LinQ-metoder kan också kombineras med vanliga LinQ-metoder. t.ex:

//using MyNamespace;
var result = Enumerable.Range(0, 13)         // generate a list
                       .Where(x => x%2 == 0) // filter the list or do something other
                       .Batch(3)             // call our extension method
                       .ToList()             // call other standard methods

Denna fråga returnerar jämna siffror grupperade i partier med storleken 3: {0, 2, 4}, {6, 8, 10}, {12}

Kom ihåg att du behöver using MyNamespace; linje för att kunna komma åt tilläggsmetoden.

Använda SelectMany istället för kapslade slingor

Får 2 listor

var list1 = new List<string> { "a", "b", "c" };
var list2 = new List<string> { "1", "2", "3", "4" };

Om du vill skriva ut alla permutationer kan du använda kapslade slingor som

var result = new List<string>();
foreach (var s1 in list1)
    foreach (var s2 in list2)
        result.Add($"{s1}{s2}");

Med SelectMany kan du utföra samma åtgärd som

var result = list1.SelectMany(x => list2.Select(y => $"{x}{y}", x, y)).ToList();

Any and First (OrDefault) - bästa praxis

Jag förklarar inte vad Any och FirstOrDefault gör eftersom det redan finns två bra exempel på dem. Se Alla och First, FirstOrDefault, Last, LastOrDefault, Single och SingleOrDefault för mer information.

Ett mönster jag ofta ser i kod som bör undvikas är

if (myEnumerable.Any(t=>t.Foo == "Bob"))
{
    var myFoo = myEnumerable.First(t=>t.Foo == "Bob");
    //Do stuff
}

Det kan skrivas mer effektivt så här

var myFoo = myEnumerable.FirstOrDefault(t=>t.Foo == "Bob");
if (myFoo != null)
{
    //Do stuff
}

Genom att använda det andra exemplet söker man i samlingen bara en gång och ger samma resultat som det första. Samma idé kan tillämpas på Single .

GroupBy Sum och Count

Låt oss ta en provklass:

public class Transaction
{
    public string Category { get; set; }
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
}

Låt oss nu ta en lista över transaktioner:

var transactions = new List<Transaction>
{
   new Transaction { Category = "Saving Account", Amount = 56, Date = DateTime.Today.AddDays(1) },
   new Transaction { Category = "Saving Account", Amount = 10, Date = DateTime.Today.AddDays(-10) },
   new Transaction { Category = "Credit Card", Amount = 15, Date = DateTime.Today.AddDays(1) },
   new Transaction { Category = "Credit Card", Amount = 56, Date = DateTime.Today },
   new Transaction { Category = "Current Account", Amount = 100, Date = DateTime.Today.AddDays(5) },
};

Om du vill beräkna summan av summan och räkna kan du använda GroupBy enligt följande:

var summaryApproach1 = transactions.GroupBy(t => t.Category)
                           .Select(t => new
                           {
                               Category = t.Key,
                               Count = t.Count(),
                               Amount = t.Sum(ta => ta.Amount),
                           }).ToList();

Console.WriteLine("-- Summary: Approach 1 --");
summaryApproach1.ForEach(
            row => Console.WriteLine($"Category: {row.Category}, Amount: {row.Amount}, Count: {row.Count}"));

Alternativt kan du göra detta i ett steg:

var summaryApproach2 = transactions.GroupBy(t => t.Category, (key, t) =>
{
        var transactionArray = t as Transaction[] ?? t.ToArray();
        return new
        {
            Category = key,
            Count = transactionArray.Length,
            Amount = transactionArray.Sum(ta => ta.Amount),
        };
}).ToList();

Console.WriteLine("-- Summary: Approach 2 --");
summaryApproach2.ForEach(
row => Console.WriteLine($"Category: {row.Category}, Amount: {row.Amount}, Count: {row.Count}"));

Output för båda ovanstående frågor skulle vara samma:

Kategori: Spara konto, Belopp: 66, Antal: 2

Kategori: Kreditkort, Belopp: 71, Räkning: 2

Kategori: Löpande konto, Belopp: 100, Räkning: 1

Live Demo i .NET Fiddle

Omvänd

  • Inverterar ordning på elementen i en sekvens.
  • Om det inte finns några objekt kastar en ArgumentNullException: source is null.

Exempel:

// Create an array.
int[] array = { 1, 2, 3, 4 };                         //Output:
// Call reverse extension method on the array.        //4
var reverse = array.Reverse();                        //3
// Write contents of array to screen.                 //2
foreach (int value in reverse)                        //1
    Console.WriteLine(value);

Exempel på levande kod

Kom ihåg att Reverse() kan fungera olika beroende på kedjan i dina LINQ-uttalanden.

        //Create List of chars
        List<int> integerlist = new List<int>() { 1, 2, 3, 4, 5, 6 };

        //Reversing the list then taking the two first elements
        IEnumerable<int> reverseFirst = integerlist.Reverse<int>().Take(2);
        
        //Taking 2 elements and then reversing only thos two
        IEnumerable<int> reverseLast = integerlist.Take(2).Reverse();
        
        //reverseFirst output: 6, 5
        //reverseLast output:  2, 1

Exempel på levande kod

Reverse () fungerar genom att buffra allt sedan gå igenom det bakåt, whitch är inte särskilt effektiv, men heller inte OrderBy från det perspektivet.

I LINQ-to-Objects finns buffertoperationer (Reverse, OrderBy, GroupBy, etc) och icke-buffertoperationer (Where, Take, Skip, etc).

Exempel: Icke-buffrande Omvänd förlängning

public static IEnumerable<T> Reverse<T>(this IList<T> list) {
    for (int i = list.Count - 1; i >= 0; i--) 
        yield return list[i];
}

Exempel på levande kod

Den här metoden kan stöta på problem om du muterar listan medan den upprepas.

Att räkna upp det antal

IEnumerable <T> -gränssnittet är basgränssnittet för alla generiska räknare och är en viktig del av att förstå LINQ. Kärnan representerar den sekvensen.

Detta underliggande gränssnitt ärvs av alla generiska samlingar, till exempel Collection <T> , Array , List <T> , Dictionary <TKey, TValue> Class och HashSet <T> .

Förutom att representera sekvensen måste varje klass som ärver från IEnumerable <T> tillhandahålla en IEnumerator <T>. Räknaren avslöjar iteratorn för de många, och dessa två sammankopplade gränssnitt och idéer är källan till ordspråket "räkna upp det räknade".

"Att räkna upp det många" är en viktig fras. Det många är helt enkelt en struktur för att iterera, det innehåller inga materialiserade objekt. Till exempel, vid sortering kan en mängd innehålla kriterierna för fältet att sortera, men med .OrderBy() i sig kommer att returnera en IEnumerable <T> som bara vet hur man ska sortera. Att använda ett samtal som kommer att materialisera objekten, som i iterera uppsättningen, kallas uppräkning (till exempel. .ToList() ). Uppräkningsprocessen kommer att använda den otaliga definitionen av hur man kan röra sig genom serien och returnera relevanta objekt (i ordning, filtrerad, projicerad, etc.).

Först när det numrerade har räknats upp orsakar det materialiseringen av objekten, det är när mätningar som tidskomplexitet (hur lång tid det ska ta relaterat till seriestorlek) och rymdkomplexitet (hur mycket utrymme det ska använda relaterat till seriestorlek) kan mätas.

Att skapa din egen klass som ärver från IEnumerable <T> kan vara lite komplicerat beroende på den underliggande serien som måste vara många. I allmänhet är det bäst att använda en av de befintliga generiska samlingarna. Som sagt är det också möjligt att ärva från IEnumerable <T> gränssnittet utan att ha en definierad grupp som den underliggande strukturen.

Använd till exempel Fibonacci-serien som den underliggande sekvensen. Observera att samtalet till Where helt enkelt bygger upp ett IEnumerable , och det är inte förrän ett samtal att räkna upp det antal som görs att något av värdena materialiseras.

void Main()
{
    Fibonacci Fibo = new Fibonacci();
    IEnumerable<long> quadrillionplus = Fibo.Where(i => i > 1000000000000);
    Console.WriteLine("Enumerable built");
    Console.WriteLine(quadrillionplus.Take(2).Sum());
    Console.WriteLine(quadrillionplus.Skip(2).First());

    IEnumerable<long> fibMod612 = Fibo.OrderBy(i => i % 612);
    Console.WriteLine("Enumerable built");
    Console.WriteLine(fibMod612.First());//smallest divisible by 612
}

public class Fibonacci : IEnumerable<long>
{
    private int max = 90;

    //Enumerator called typically from foreach
    public IEnumerator GetEnumerator() {
        long n0 = 1;
        long n1 = 1;
        Console.WriteLine("Enumerating the Enumerable");
        for(int i = 0; i < max; i++){
            yield return n0+n1;
            n1 += n0;
            n0 = n1-n0;
        }
    }
    
    //Enumerable called typically from linq
    IEnumerator<long> IEnumerable<long>.GetEnumerator() {
        long n0 = 1;
        long n1 = 1;
        Console.WriteLine("Enumerating the Enumerable");
        for(int i = 0; i < max; i++){
            yield return n0+n1;
            n1 += n0;
            n0 = n1-n0;
        }
    }
}

Produktion

Enumerable built
Enumerating the Enumerable
4052739537881
Enumerating the Enumerable
4052739537881
Enumerable built
Enumerating the Enumerable
14930352

Styrkan i den andra uppsättningen (fibMod612) är att även om vi ringde att beställa hela vår uppsättning Fibonacci-nummer, eftersom endast ett värde togs med hjälp av. .First() var tidskomplexiteten O (n) som endast 1 värde behövde jämföras under exekveringen av beställningsalgoritmen. Detta beror på att vår räknare bara bad om ett värde, och därför behövde inte hela materialet bli materialiserat. Hade vi använt. .Take(5) istället för. .First() skulle uppräknaren ha bett om 5 värden, och högst 5 värden skulle behöva materialiseras. Jämfört med att behöva beställa en hel uppsättning och sedan ta de första fem värdena, sparar principen för mycket körningstid och utrymme.

Sortera efter

Beställer en samling med ett angivet värde.

När värdet är ett heltal , dubbla eller flyta börjar det med minimivärdet , vilket innebär att du först får de negativa värdena än noll och efterhand de positiva värdena (se exempel 1).

När du beställer enligt en ruta jämför metoden ascii-värdena på tecknen för att sortera samlingen (se exempel 2).

När du sorterar strängar jämför OrderBy-metoden dem genom att titta på deras CultureInfo men normalt sett börjar med den första bokstaven i alfabetet (a, b, c ...).

Denna typ av beställning kallas stigande, om du vill ha det tvärtom behöver du gå ner (se OrderByDescending).

Exempel 1:

int[] numbers = {2, 1, 0, -1, -2};
IEnumerable<int> ascending = numbers.OrderBy(x => x);
// returns {-2, -1, 0, 1, 2}

Exempel 2:

 char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z', 'Z'};
 IEnumerable<char> ascending = letters.OrderBy(x => x);
 // returns { ' ', '!', '+', '1', '9', '?', 'A', 'B', 'Y', 'Z', '[', 'a', 'b', 'y', 'z', '{' }

Exempel:

class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
}

var people = new[]
{
    new Person {Name = "Alice", Age = 25},
    new Person {Name = "Bob", Age = 21},
    new Person {Name = "Carol", Age = 43}
};
var youngestPerson = people.OrderBy(x => x.Age).First();
var name = youngestPerson.Name; // Bob

OrderByDescending

Beställer en samling med ett angivet värde.

När värdet är ett heltal , dubbel eller flytande börjar det med det maximala värdet , vilket innebär att du först får de positiva värdena än noll och efterhand de negativa värdena (se exempel 1).

När du beställer enligt en ruta jämför metoden ascii-värdena på tecknen för att sortera samlingen (se exempel 2).

När du sorterar strängar jämför OrderBy-metoden dem genom att titta på deras CultureInfo men normalt sett börjar med den sista bokstaven i alfabetet (z, y, x, ...).

Denna typ av ordning kallas fallande, om du vill ha det tvärtom behöver du stigande (se OrderBy).

Exempel 1:

int[] numbers = {-2, -1, 0, 1, 2};
IEnumerable<int> descending = numbers.OrderByDescending(x => x);
// returns {2, 1, 0, -1, -2}

Exempel 2:

char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z', 'Z'};
IEnumerable<char> descending = letters.OrderByDescending(x => x);
// returns { '{', 'z', 'y', 'b', 'a', '[', 'Z', 'Y', 'B', 'A', '?', '9', '1', '+', '!', ' ' }

Exempel 3:

class Person
{
   public  string Name { get; set; }
   public  int Age { get; set; }
}

var people = new[]
{
    new Person {Name = "Alice", Age = 25},
    new Person {Name = "Bob", Age = 21},
    new Person {Name = "Carol", Age = 43}
};
var oldestPerson = people.OrderByDescending(x => x.Age).First();
var name = oldestPerson.Name; // Carol

concat

Slår samman två samlingar (utan att ta bort dubbletter)

List<int> foo = new List<int> { 1, 2, 3 };
List<int> bar = new List<int> { 3, 4, 5 };

// Through Enumerable static class
var result = Enumerable.Concat(foo, bar).ToList(); // 1,2,3,3,4,5

// Through extension method
var result = foo.Concat(bar).ToList(); // 1,2,3,3,4,5

innehåller

MSDN:

Bestämmer om en sekvens innehåller ett specificerat element med hjälp av en specificerad IEqualityComparer<T>

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var result1 = numbers.Contains(4); // true
var result2 = numbers.Contains(8); // false

List<int> secondNumberCollection = new List<int> { 4, 5, 6, 7 };
// Note that can use the Intersect method in this case
var result3 = secondNumberCollection.Where(item => numbers.Contains(item)); // will be true only for 4,5

Använda ett användardefinierat objekt:

public class Person
{
   public string Name { get; set; }
}

List<Person> objects = new List<Person>
{
    new Person { Name = "Nikki"},
    new Person { Name = "Gilad"},
    new Person { Name = "Phil"},
    new Person { Name = "John"}
};

//Using the Person's Equals method - override Equals() and GetHashCode() - otherwise it
//will compare by reference and result will be false
var result4 = objects.Contains(new Person { Name = "Phil" }); // true

Använda Enumerable.Contains(value, comparer) överbelastning:

public class Compare : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Name == y.Name;
    }
    public int GetHashCode(Person codeh)
    {
        return codeh.Name.GetHashCode();
    }
}

var result5 = objects.Contains(new Person { Name = "Phil" }, new Compare()); // true

En smart användning av Contains skulle vara att ersätta flera if klausuler till ett Contains samtal.

Så istället för att göra detta:

if(status == 1 || status == 3 || status == 4)
{
    //Do some business operation
}
else
{
    //Do something else
}

Gör det här:

if(new int[] {1, 3, 4 }.Contains(status)
{
    //Do some business operaion
}
else 
{
    //Do something else
}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow