System.InvalidOperationException-klass
Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.
InvalidOperationException används i fall då misslyckandet med att anropa en metod orsakas av andra orsaker än ogiltiga argument. Vanligtvis genereras det när tillståndet för ett objekt inte stöder metodanropet. Ett undantag genereras till exempel InvalidOperationException av metoder som:
- IEnumerator.MoveNext om objekt i en samling ändras när uppräknaren har skapats. Mer information finns i Ändra en samling när den itererar den.
- ResourceSet.GetString om resursuppsättningen stängs innan metodanropet görs.
- XContainer.Add, om objektet eller objekten som ska läggas till skulle resultera i ett felaktigt strukturerat XML-dokument.
- En metod som försöker manipulera användargränssnittet från en tråd som inte är huvudtråden eller användargränssnittstråden.
Viktigt!
Eftersom undantaget InvalidOperationException kan genereras under en mängd olika omständigheter är det viktigt att läsa undantagsmeddelandet som returneras av Message egenskapen.
InvalidOperationException använder HRESULT COR_E_INVALIDOPERATION
, som har värdet 0x80131509.
En lista över inledande egenskapsvärden för en instans av InvalidOperationExceptionfinns i InvalidOperationException konstruktorerna.
Vanliga orsaker till InvalidOperationException-undantag
Följande avsnitt visar hur vissa vanliga fall där InvalidOperationException undantag utlöses i en app. Hur du hanterar problemet beror på den specifika situationen. Det vanligaste undantaget beror dock på utvecklarfel och undantaget InvalidOperationException kan förväntas och undvikas.
Uppdatera en användargränssnittstråd från en tråd som inte är användargränssnitt
Ofta används arbetstrådar för att utföra bakgrundsarbete som omfattar insamling av data som ska visas i ett programs användargränssnitt. Emellertid. De flesta GUI-programramverk (grafiskt användargränssnitt) för .NET, till exempel Windows Forms och Windows Presentation Foundation (WPF), ger dig endast åtkomst till GUI-objekt från tråden som skapar och hanterar användargränssnittet (huvud- eller användargränssnittstråden). Ett InvalidOperationException utlöses när du försöker komma åt ett gränssnittselement från en annan tråd än användargränssnittstråden. Texten i undantagsmeddelandet visas i följande tabell.
Programtyp | Meddelande |
---|---|
WPF-app | Den anropande tråden kan inte komma åt det här objektet eftersom en annan tråd äger det. |
UWP-app | Programmet anropade ett gränssnitt som har konverterats för en annan tråd. |
Windows Forms-app | Åtgärden mellan trådar är inte giltig: Kontrollera "TextBox1" som nås från en annan tråd än den tråd som den skapades på. |
Användargränssnittsramverk för .NET implementerar ett dispatcher-mönster som innehåller en metod för att kontrollera om ett anrop till en medlem i ett användargränssnittselement körs i användargränssnittstråden och andra metoder för att schemalägga anropet i användargränssnittstråden:
- I WPF-appar anropar du Dispatcher.CheckAccess metoden för att avgöra om en metod körs på en tråd som inte är en användargränssnittstråd. Den returnerar
true
om metoden körs i användargränssnittstråden ochfalse
annars. Anropa en av överlagringarna av Dispatcher.Invoke metoden för att schemalägga anropet i användargränssnittstråden. - I UWP-appar kontrollerar du CoreDispatcher.HasThreadAccess egenskapen för att avgöra om en metod körs på en tråd som inte är användargränssnitt. CoreDispatcher.RunAsync Anropa metoden för att köra ett ombud som uppdaterar användargränssnittstråden.
- I Windows Forms-appar använder du Control.InvokeRequired egenskapen för att avgöra om en metod körs på en tråd som inte är användargränssnitt. Anropa en av överlagringarna av Control.Invoke metoden för att köra ett ombud som uppdaterar användargränssnittstråden.
Följande exempel illustrerar undantaget InvalidOperationException som utlöses när du försöker uppdatera ett användargränssnittselement från en annan tråd än tråden som skapade det. Varje exempel kräver att du skapar två kontroller:
- En textrutekontroll med namnet
textBox1
. I en Windows Forms-app bör du ange dess Multiline egenskap tilltrue
. - En knappkontroll med namnet
threadExampleBtn
. Exemplet innehåller en hanterare,ThreadsExampleBtn_Click
, för knappensClick
händelse.
I varje fall threadExampleBtn_Click
anropar DoSomeWork
händelsehanteraren metoden två gånger. Det första anropet körs synkront och lyckas. Men det andra anropet, eftersom det körs asynkront på en trådpoolstråd, försöker uppdatera användargränssnittet från en tråd som inte är användargränssnitt. Detta resulterar i ett InvalidOperationException undantag.
WPF-appar
private async void threadExampleBtn_Click(object sender, RoutedEventArgs e)
{
textBox1.Text = String.Empty;
textBox1.Text = "Simulating work on UI thread.\n";
DoSomeWork(20);
textBox1.Text += "Work completed...\n";
textBox1.Text += "Simulating work on non-UI thread.\n";
await Task.Run(() => DoSomeWork(1000));
textBox1.Text += "Work completed...\n";
}
private async void DoSomeWork(int milliseconds)
{
// Simulate work.
await Task.Delay(milliseconds);
// Report completion.
var msg = String.Format("Some work completed in {0} ms.\n", milliseconds);
textBox1.Text += msg;
}
Följande version av DoSomeWork
metoden eliminerar undantaget i en WPF-app.
private async void DoSomeWork(int milliseconds)
{
// Simulate work.
await Task.Delay(milliseconds);
// Report completion.
bool uiAccess = textBox1.Dispatcher.CheckAccess();
String msg = String.Format("Some work completed in {0} ms. on {1}UI thread\n",
milliseconds, uiAccess ? String.Empty : "non-");
if (uiAccess)
textBox1.Text += msg;
else
textBox1.Dispatcher.Invoke(() => { textBox1.Text += msg; });
}
Windows Forms-appar
List<String> lines = new List<String>();
private async void threadExampleBtn_Click(object sender, EventArgs e)
{
textBox1.Text = String.Empty;
lines.Clear();
lines.Add("Simulating work on UI thread.");
textBox1.Lines = lines.ToArray();
DoSomeWork(20);
lines.Add("Simulating work on non-UI thread.");
textBox1.Lines = lines.ToArray();
await Task.Run(() => DoSomeWork(1000));
lines.Add("ThreadsExampleBtn_Click completes. ");
textBox1.Lines = lines.ToArray();
}
private async void DoSomeWork(int milliseconds)
{
// simulate work
await Task.Delay(milliseconds);
// report completion
lines.Add(String.Format("Some work completed in {0} ms on UI thread.", milliseconds));
textBox1.Lines = lines.ToArray();
}
Dim lines As New List(Of String)()
Private Async Sub threadExampleBtn_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = String.Empty
lines.Clear()
lines.Add("Simulating work on UI thread.")
TextBox1.Lines = lines.ToArray()
DoSomeWork(20)
lines.Add("Simulating work on non-UI thread.")
TextBox1.Lines = lines.ToArray()
Await Task.Run(Sub() DoSomeWork(1000))
lines.Add("ThreadsExampleBtn_Click completes. ")
TextBox1.Lines = lines.ToArray()
End Sub
Private Async Sub DoSomeWork(milliseconds As Integer)
' Simulate work.
Await Task.Delay(milliseconds)
' Report completion.
lines.Add(String.Format("Some work completed in {0} ms on UI thread.", milliseconds))
textBox1.Lines = lines.ToArray()
End Sub
Följande version av DoSomeWork
metoden eliminerar undantaget i en Windows Forms-app.
private async void DoSomeWork(int milliseconds)
{
// simulate work
await Task.Delay(milliseconds);
// Report completion.
bool uiMarshal = textBox1.InvokeRequired;
String msg = String.Format("Some work completed in {0} ms. on {1}UI thread\n",
milliseconds, uiMarshal ? String.Empty : "non-");
lines.Add(msg);
if (uiMarshal) {
textBox1.Invoke(new Action(() => { textBox1.Lines = lines.ToArray(); }));
}
else {
textBox1.Lines = lines.ToArray();
}
}
Private Async Sub DoSomeWork(milliseconds As Integer)
' Simulate work.
Await Task.Delay(milliseconds)
' Report completion.
Dim uiMarshal As Boolean = TextBox1.InvokeRequired
Dim msg As String = String.Format("Some work completed in {0} ms. on {1}UI thread" + vbCrLf,
milliseconds, If(uiMarshal, String.Empty, "non-"))
lines.Add(msg)
If uiMarshal Then
TextBox1.Invoke(New Action(Sub() TextBox1.Lines = lines.ToArray()))
Else
TextBox1.Lines = lines.ToArray()
End If
End Sub
Ändra en samling när den itererar den
-instruktionen foreach
i C#, for...in
i F# eller For Each
-instruktionen i Visual Basic används för att iterera medlemmarna i en samling och för att läsa eller ändra dess enskilda element. Det kan dock inte användas för att lägga till eller ta bort objekt från samlingen. Om du gör detta genereras ett InvalidOperationException undantag med ett meddelande som liknar "Samlingen har ändrats; uppräkningsåtgärden kanske inte körs."
I följande exempel itererar en samling heltalsförsök att lägga till kvadraten för varje heltal i samlingen. Exemplet genererar ett InvalidOperationException med det första anropet List<T>.Add till metoden.
using System;
using System.Collections.Generic;
public class IteratingEx1
{
public static void Main()
{
var numbers = new List<int>() { 1, 2, 3, 4, 5 };
foreach (var number in numbers)
{
int square = (int)Math.Pow(number, 2);
Console.WriteLine("{0}^{1}", number, square);
Console.WriteLine("Adding {0} to the collection...\n", square);
numbers.Add(square);
}
}
}
// The example displays the following output:
// 1^1
// Adding 1 to the collection...
//
//
// Unhandled Exception: System.InvalidOperationException: Collection was modified;
// enumeration operation may not execute.
// at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
// at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
// at Example.Main()
open System
let numbers = ResizeArray [| 1; 2; 3; 4; 5 |]
for number in numbers do
let square = Math.Pow(number, 2) |> int
printfn $"{number}^{square}"
printfn $"Adding {square} to the collection...\n"
numbers.Add square
// The example displays the following output:
// 1^1
// Adding 1 to the collection...
//
//
// Unhandled Exception: System.InvalidOperationException: Collection was modified
// enumeration operation may not execute.
// at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
// at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
// at <StartupCode$fs>.main()
Imports System.Collections.Generic
Module Example6
Public Sub Main()
Dim numbers As New List(Of Integer)({1, 2, 3, 4, 5})
For Each number In numbers
Dim square As Integer = CInt(Math.Pow(number, 2))
Console.WriteLine("{0}^{1}", number, square)
Console.WriteLine("Adding {0} to the collection..." + vbCrLf,
square)
numbers.Add(square)
Next
End Sub
End Module
' The example displays the following output:
' 1^1
' Adding 1 to the collection...
'
'
' Unhandled Exception: System.InvalidOperationException: Collection was modified;
' enumeration operation may not execute.
' at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
' at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
' at Example.Main()
Du kan eliminera undantaget på ett av två sätt, beroende på din programlogik:
Om element måste läggas till i samlingen när den itereras kan du iterera den med hjälp av instruktionen
for
(for..to
i F#) i stället förforeach
,for...in
ellerFor Each
. I följande exempel används for-instruktionen för att lägga till kvadraten med tal i samlingen i samlingen.using System; using System.Collections.Generic; public class IteratingEx2 { public static void Main() { var numbers = new List<int>() { 1, 2, 3, 4, 5 }; int upperBound = numbers.Count - 1; for (int ctr = 0; ctr <= upperBound; ctr++) { int square = (int)Math.Pow(numbers[ctr], 2); Console.WriteLine("{0}^{1}", numbers[ctr], square); Console.WriteLine("Adding {0} to the collection...\n", square); numbers.Add(square); } Console.WriteLine("Elements now in the collection: "); foreach (var number in numbers) Console.Write("{0} ", number); } } // The example displays the following output: // 1^1 // Adding 1 to the collection... // // 2^4 // Adding 4 to the collection... // // 3^9 // Adding 9 to the collection... // // 4^16 // Adding 16 to the collection... // // 5^25 // Adding 25 to the collection... // // Elements now in the collection: // 1 2 3 4 5 1 4 9 16 25
open System open System.Collections.Generic let numbers = ResizeArray [| 1; 2; 3; 4; 5 |] let upperBound = numbers.Count - 1 for i = 0 to upperBound do let square = Math.Pow(numbers[i], 2) |> int printfn $"{numbers[i]}^{square}" printfn $"Adding {square} to the collection...\n" numbers.Add square printfn "Elements now in the collection: " for number in numbers do printf $"{number} " // The example displays the following output: // 1^1 // Adding 1 to the collection... // // 2^4 // Adding 4 to the collection... // // 3^9 // Adding 9 to the collection... // // 4^16 // Adding 16 to the collection... // // 5^25 // Adding 25 to the collection... // // Elements now in the collection: // 1 2 3 4 5 1 4 9 16 25
Imports System.Collections.Generic Module Example7 Public Sub Main() Dim numbers As New List(Of Integer)({1, 2, 3, 4, 5}) Dim upperBound = numbers.Count - 1 For ctr As Integer = 0 To upperBound Dim square As Integer = CInt(Math.Pow(numbers(ctr), 2)) Console.WriteLine("{0}^{1}", numbers(ctr), square) Console.WriteLine("Adding {0} to the collection..." + vbCrLf, square) numbers.Add(square) Next Console.WriteLine("Elements now in the collection: ") For Each number In numbers Console.Write("{0} ", number) Next End Sub End Module ' The example displays the following output: ' 1^1 ' Adding 1 to the collection... ' ' 2^4 ' Adding 4 to the collection... ' ' 3^9 ' Adding 9 to the collection... ' ' 4^16 ' Adding 16 to the collection... ' ' 5^25 ' Adding 25 to the collection... ' ' Elements now in the collection: ' 1 2 3 4 5 1 4 9 16 25
Observera att du måste fastställa antalet iterationer innan du itererar samlingen genom att antingen använda en räknare i loopen som avslutar loopen på rätt sätt, genom att iterera bakåt, från
Count
- 1 till 0, eller, som exemplet gör, genom att tilldela antalet element i matrisen till en variabel och använda den för att upprätta den övre gränsen för loopen. Annars, om ett element läggs till i samlingen vid varje iteration, resulterar en oändlig loop.Om det inte är nödvändigt att lägga till element i samlingen när den itereras kan du lagra elementen som ska läggas till i en tillfällig samling som du lägger till när iterering av samlingen har slutförts. I följande exempel används den här metoden för att lägga till kvadraten med tal i en samling till en tillfällig samling och sedan kombinera samlingarna till ett enda matrisobjekt.
using System; using System.Collections.Generic; public class IteratingEx3 { public static void Main() { var numbers = new List<int>() { 1, 2, 3, 4, 5 }; var temp = new List<int>(); // Square each number and store it in a temporary collection. foreach (var number in numbers) { int square = (int)Math.Pow(number, 2); temp.Add(square); } // Combine the numbers into a single array. int[] combined = new int[numbers.Count + temp.Count]; Array.Copy(numbers.ToArray(), 0, combined, 0, numbers.Count); Array.Copy(temp.ToArray(), 0, combined, numbers.Count, temp.Count); // Iterate the array. foreach (var value in combined) Console.Write("{0} ", value); } } // The example displays the following output: // 1 2 3 4 5 1 4 9 16 25
open System open System.Collections.Generic let numbers = ResizeArray [| 1; 2; 3; 4; 5 |] let temp = ResizeArray() // Square each number and store it in a temporary collection. for number in numbers do let square = Math.Pow(number, 2) |> int temp.Add square // Combine the numbers into a single array. let combined = Array.zeroCreate<int> (numbers.Count + temp.Count) Array.Copy(numbers.ToArray(), 0, combined, 0, numbers.Count) Array.Copy(temp.ToArray(), 0, combined, numbers.Count, temp.Count) // Iterate the array. for value in combined do printf $"{value} " // The example displays the following output: // 1 2 3 4 5 1 4 9 16 25
Imports System.Collections.Generic Module Example8 Public Sub Main() Dim numbers As New List(Of Integer)({1, 2, 3, 4, 5}) Dim temp As New List(Of Integer)() ' Square each number and store it in a temporary collection. For Each number In numbers Dim square As Integer = CInt(Math.Pow(number, 2)) temp.Add(square) Next ' Combine the numbers into a single array. Dim combined(numbers.Count + temp.Count - 1) As Integer Array.Copy(numbers.ToArray(), 0, combined, 0, numbers.Count) Array.Copy(temp.ToArray(), 0, combined, numbers.Count, temp.Count) ' Iterate the array. For Each value In combined Console.Write("{0} ", value) Next End Sub End Module ' The example displays the following output: ' 1 2 3 4 5 1 4 9 16 25
Sortera en matris eller samling vars objekt inte kan jämföras
Allmänna sorteringsmetoder, till exempel Array.Sort(Array) metoden eller List<T>.Sort() metoden, kräver vanligtvis att minst ett av objekten sorteras för att implementera IComparable<T> gränssnittet eller IComparable . Om inte kan samlingen eller matrisen inte sorteras, och metoden genererar ett InvalidOperationException undantag. I följande exempel definieras en Person
klass, två Person
objekt lagras i ett allmänt List<T> objekt och försök att sortera dem. Som utdata från exemplet visar anropet List<T>.Sort() till metoden genererar en InvalidOperationException.
using System;
using System.Collections.Generic;
public class Person1
{
public Person1(string fName, string lName)
{
FirstName = fName;
LastName = lName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class ListSortEx1
{
public static void Main()
{
var people = new List<Person1>();
people.Add(new Person1("John", "Doe"));
people.Add(new Person1("Jane", "Doe"));
people.Sort();
foreach (var person in people)
Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}
}
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. --->
// System.ArgumentException: At least one object must implement IComparable.
// at System.Collections.Comparer.Compare(Object a, Object b)
// at System.Collections.Generic.ArraySortHelper`1.SwapIfGreater(T[] keys, IComparer`1 comparer, Int32 a, Int32 b)
// at System.Collections.Generic.ArraySortHelper`1.DepthLimitedQuickSort(T[] keys, Int32 left, Int32 right, IComparer`1 comparer, Int32 depthLimit)
// at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
// --- End of inner exception stack trace ---
// at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
// at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
// at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
// at Example.Main()
type Person(firstName: string, lastName: string) =
member val FirstName = firstName with get, set
member val LastName = lastName with get, set
let people = ResizeArray()
people.Add(Person("John", "Doe"))
people.Add(Person("Jane", "Doe"))
people.Sort()
for person in people do
printfn $"{person.FirstName} {person.LastName}"
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. --->
// System.ArgumentException: At least one object must implement IComparable.
// at System.Collections.Comparer.Compare(Object a, Object b)
// at System.Collections.Generic.ArraySortHelper`1.SwapIfGreater(T[] keys, IComparer`1 comparer, Int32 a, Int32 b)
// at System.Collections.Generic.ArraySortHelper`1.DepthLimitedQuickSort(T[] keys, Int32 left, Int32 right, IComparer`1 comparer, Int32 depthLimit)
// at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
// --- End of inner exception stack trace ---
// at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
// at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
// at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
// at <StartupCode$fs>.main()
Imports System.Collections.Generic
Public Class Person9
Public Sub New(fName As String, lName As String)
FirstName = fName
LastName = lName
End Sub
Public Property FirstName As String
Public Property LastName As String
End Class
Module Example9
Public Sub Main()
Dim people As New List(Of Person9)()
people.Add(New Person9("John", "Doe"))
people.Add(New Person9("Jane", "Doe"))
people.Sort()
For Each person In people
Console.WriteLine("{0} {1}", person.FirstName, person.LastName)
Next
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. --->
' System.ArgumentException: At least one object must implement IComparable.
' at System.Collections.Comparer.Compare(Object a, Object b)
' at System.Collections.Generic.ArraySortHelper`1.SwapIfGreater(T[] keys, IComparer`1 comparer, Int32 a, Int32 b)
' at System.Collections.Generic.ArraySortHelper`1.DepthLimitedQuickSort(T[] keys, Int32 left, Int32 right, IComparer`1 comparer, Int32 depthLimit)
' at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
' --- End of inner exception stack trace ---
' at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
' at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
' at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
' at Example.Main()
Du kan eliminera undantaget på något av tre sätt:
Om du kan äga den typ som du försöker sortera (d.v.s. om du kontrollerar källkodenIComparable) kan du ändra den för att implementera IComparable<T> gränssnittet eller . Detta kräver att du implementerar antingen IComparable<T>.CompareToCompareTo eller -metoden. Att lägga till en gränssnittsimplementering till en befintlig typ är inte en icke-bakåtkompatibel ändring.
I följande exempel används den här metoden för att tillhandahålla en IComparable<T> implementering för
Person
klassen. Du kan fortfarande anropa samlingens eller matrisens allmänna sorteringsmetod och, som utdata från exemplet visar, sorterar samlingen korrekt.using System; using System.Collections.Generic; public class Person2 : IComparable<Person> { public Person2(String fName, String lName) { FirstName = fName; LastName = lName; } public String FirstName { get; set; } public String LastName { get; set; } public int CompareTo(Person other) { return String.Format("{0} {1}", LastName, FirstName). CompareTo(String.Format("{0} {1}", other.LastName, other.FirstName)); } } public class ListSortEx2 { public static void Main() { var people = new List<Person2>(); people.Add(new Person2("John", "Doe")); people.Add(new Person2("Jane", "Doe")); people.Sort(); foreach (var person in people) Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } } // The example displays the following output: // Jane Doe // John Doe
open System type Person(firstName: string, lastName: string) = member val FirstName = firstName with get, set member val LastName = lastName with get, set interface IComparable<Person> with member this.CompareTo(other) = compare $"{this.LastName} {this.FirstName}" $"{other.LastName} {other.FirstName}" let people = ResizeArray() people.Add(new Person("John", "Doe")) people.Add(new Person("Jane", "Doe")) people.Sort() for person in people do printfn $"{person.FirstName} {person.LastName}" // The example displays the following output: // Jane Doe // John Doe
Imports System.Collections.Generic Public Class Person : Implements IComparable(Of Person) Public Sub New(fName As String, lName As String) FirstName = fName LastName = lName End Sub Public Property FirstName As String Public Property LastName As String Public Function CompareTo(other As Person) As Integer _ Implements IComparable(Of Person).CompareTo Return String.Format("{0} {1}", LastName, FirstName). CompareTo(String.Format("{0} {1}", other.LastName, other.FirstName)) End Function End Class Module Example10 Public Sub Main() Dim people As New List(Of Person)() people.Add(New Person("John", "Doe")) people.Add(New Person("Jane", "Doe")) people.Sort() For Each person In people Console.WriteLine("{0} {1}", person.FirstName, person.LastName) Next End Sub End Module ' The example displays the following output: ' Jane Doe ' John Doe
Om du inte kan ändra källkoden för den typ som du försöker sortera kan du definiera en specialsorteringsklass som implementerar IComparer<T> gränssnittet. Du kan anropa en överlagring av metoden
Sort
som innehåller en IComparer<T> parameter. Den här metoden är särskilt användbar om du vill utveckla en specialiserad sorteringsklass som kan sortera objekt baserat på flera villkor.I följande exempel används metoden genom att utveckla en anpassad
PersonComparer
klass som används för att sorteraPerson
samlingar. Sedan skickas en instans av den här klassen till List<T>.Sort(IComparer<T>) metoden.using System; using System.Collections.Generic; public class Person3 { public Person3(String fName, String lName) { FirstName = fName; LastName = lName; } public String FirstName { get; set; } public String LastName { get; set; } } public class PersonComparer : IComparer<Person3> { public int Compare(Person3 x, Person3 y) { return String.Format("{0} {1}", x.LastName, x.FirstName). CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName)); } } public class ListSortEx3 { public static void Main() { var people = new List<Person3>(); people.Add(new Person3("John", "Doe")); people.Add(new Person3("Jane", "Doe")); people.Sort(new PersonComparer()); foreach (var person in people) Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } } // The example displays the following output: // Jane Doe // John Doe
open System open System.Collections.Generic type Person(firstName, lastName) = member val FirstName = firstName with get, set member val LastName = lastName with get, set type PersonComparer() = interface IComparer<Person> with member _.Compare(x: Person, y: Person) = $"{x.LastName} {x.FirstName}".CompareTo $"{y.LastName} {y.FirstName}" let people = ResizeArray() people.Add(Person("John", "Doe")) people.Add(Person("Jane", "Doe")) people.Sort(PersonComparer()) for person in people do printfn $"{person.FirstName} {person.LastName}" // The example displays the following output: // Jane Doe // John Doe
Imports System.Collections.Generic Public Class Person11 Public Sub New(fName As String, lName As String) FirstName = fName LastName = lName End Sub Public Property FirstName As String Public Property LastName As String End Class Public Class PersonComparer : Implements IComparer(Of Person11) Public Function Compare(x As Person11, y As Person11) As Integer _ Implements IComparer(Of Person11).Compare Return String.Format("{0} {1}", x.LastName, x.FirstName). CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName)) End Function End Class Module Example11 Public Sub Main() Dim people As New List(Of Person11)() people.Add(New Person11("John", "Doe")) people.Add(New Person11("Jane", "Doe")) people.Sort(New PersonComparer()) For Each person In people Console.WriteLine("{0} {1}", person.FirstName, person.LastName) Next End Sub End Module ' The example displays the following output: ' Jane Doe ' John Doe
Om du inte kan ändra källkoden för den typ som du försöker sortera kan du skapa ett Comparison<T> ombud för att utföra sortering. Ombudssignaturen är
Function Comparison(Of T)(x As T, y As T) As Integer
int Comparison<T>(T x, T y)
I följande exempel används metoden genom att definiera en
PersonComparison
metod som matchar ombudets Comparison<T> signatur. Den skickar sedan det här ombudet List<T>.Sort(Comparison<T>) till metoden.using System; using System.Collections.Generic; public class Person { public Person(String fName, String lName) { FirstName = fName; LastName = lName; } public String FirstName { get; set; } public String LastName { get; set; } } public class ListSortEx4 { public static void Main() { var people = new List<Person>(); people.Add(new Person("John", "Doe")); people.Add(new Person("Jane", "Doe")); people.Sort(PersonComparison); foreach (var person in people) Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } public static int PersonComparison(Person x, Person y) { return String.Format("{0} {1}", x.LastName, x.FirstName). CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName)); } } // The example displays the following output: // Jane Doe // John Doe
open System open System.Collections.Generic type Person(firstName, lastName) = member val FirstName = firstName with get, set member val LastName = lastName with get, set let personComparison (x: Person) (y: Person) = $"{x.LastName} {x.FirstName}".CompareTo $"{y.LastName} {y.FirstName}" let people = ResizeArray() people.Add(Person("John", "Doe")) people.Add(Person("Jane", "Doe")) people.Sort personComparison for person in people do printfn $"{person.FirstName} {person.LastName}" // The example displays the following output: // Jane Doe // John Doe
Imports System.Collections.Generic Public Class Person12 Public Sub New(fName As String, lName As String) FirstName = fName LastName = lName End Sub Public Property FirstName As String Public Property LastName As String End Class Module Example12 Public Sub Main() Dim people As New List(Of Person12)() people.Add(New Person12("John", "Doe")) people.Add(New Person12("Jane", "Doe")) people.Sort(AddressOf PersonComparison) For Each person In people Console.WriteLine("{0} {1}", person.FirstName, person.LastName) Next End Sub Public Function PersonComparison(x As Person12, y As Person12) As Integer Return String.Format("{0} {1}", x.LastName, x.FirstName). CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName)) End Function End Module ' The example displays the following output: ' Jane Doe ' John Doe
Gjuta ett nullbart<T> som är null till dess underliggande typ
Försök att omvandla ett Nullable<T> värde som är null
till dess underliggande typ genererar ett InvalidOperationException undantag och visar felmeddelandet "Nullable object must have a value( Nullable object must have a value.
I följande exempel genereras ett InvalidOperationException undantag när det försöker iterera en matris som innehåller ett Nullable(Of Integer)
värde.
using System;
using System.Linq;
public class NullableEx1
{
public static void Main()
{
var queryResult = new int?[] { 1, 2, null, 4 };
var map = queryResult.Select(nullableInt => (int)nullableInt);
// Display list.
foreach (var num in map)
Console.Write("{0} ", num);
Console.WriteLine();
}
}
// The example displays the following output:
// 1 2
// Unhandled Exception: System.InvalidOperationException: Nullable object must have a value.
// at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
// at Example.<Main>b__0(Nullable`1 nullableInt)
// at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
// at Example.Main()
open System
open System.Linq
let queryResult = [| Nullable 1; Nullable 2; Nullable(); Nullable 4 |]
let map = queryResult.Select(fun nullableInt -> nullableInt.Value)
// Display list.
for num in map do
printf $"{num} "
printfn ""
// The example displays the following output:
// 1 2
// Unhandled Exception: System.InvalidOperationException: Nullable object must have a value.
// at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
// at Example.<Main>b__0(Nullable`1 nullableInt)
// at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
// at <StartupCode$fs>.main()
Imports System.Linq
Module Example13
Public Sub Main()
Dim queryResult = New Integer?() {1, 2, Nothing, 4}
Dim map = queryResult.Select(Function(nullableInt) CInt(nullableInt))
' Display list.
For Each num In map
Console.Write("{0} ", num)
Next
Console.WriteLine()
End Sub
End Module
' The example displays thIe following output:
' 1 2
' Unhandled Exception: System.InvalidOperationException: Nullable object must have a value.
' at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
' at Example.<Main>b__0(Nullable`1 nullableInt)
' at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
' at Example.Main()
Så här förhindrar du undantaget:
- Använd egenskapen Nullable<T>.HasValue för att välja endast de element som inte
null
är . - Anropa en av överlagringarna Nullable<T>.GetValueOrDefault för att ange ett standardvärde för ett
null
värde.
Följande exempel gör båda för att undvika undantaget InvalidOperationException .
using System;
using System.Linq;
public class NullableEx2
{
public static void Main()
{
var queryResult = new int?[] { 1, 2, null, 4 };
var numbers = queryResult.Select(nullableInt => (int)nullableInt.GetValueOrDefault());
// Display list using Nullable<int>.HasValue.
foreach (var number in numbers)
Console.Write("{0} ", number);
Console.WriteLine();
numbers = queryResult.Select(nullableInt => (int) (nullableInt.HasValue ? nullableInt : -1));
// Display list using Nullable<int>.GetValueOrDefault.
foreach (var number in numbers)
Console.Write("{0} ", number);
Console.WriteLine();
}
}
// The example displays the following output:
// 1 2 0 4
// 1 2 -1 4
open System
open System.Linq
let queryResult = [| Nullable 1; Nullable 2; Nullable(); Nullable 4 |]
let numbers = queryResult.Select(fun nullableInt -> nullableInt.GetValueOrDefault())
// Display list using Nullable<int>.HasValue.
for number in numbers do
printf $"{number} "
printfn ""
let numbers2 = queryResult.Select(fun nullableInt -> if nullableInt.HasValue then nullableInt.Value else -1)
// Display list using Nullable<int>.GetValueOrDefault.
for number in numbers2 do
printf $"{number} "
printfn ""
// The example displays the following output:
// 1 2 0 4
// 1 2 -1 4
Imports System.Linq
Module Example14
Public Sub Main()
Dim queryResult = New Integer?() {1, 2, Nothing, 4}
Dim numbers = queryResult.Select(Function(nullableInt) _
CInt(nullableInt.GetValueOrDefault()))
' Display list.
For Each number In numbers
Console.Write("{0} ", number)
Next
Console.WriteLine()
' Use -1 to indicate a missing values.
numbers = queryResult.Select(Function(nullableInt) _
CInt(If(nullableInt.HasValue, nullableInt, -1)))
' Display list.
For Each number In numbers
Console.Write("{0} ", number)
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' 1 2 0 4
' 1 2 -1 4
Anropa en System.Linq.Enumerable-metod i en tom samling
Metoderna Enumerable.Aggregate, Enumerable.Average, Enumerable.First, Enumerable.Last, Enumerable.MaxEnumerable.Min, , Enumerable.Singleoch Enumerable.SingleOrDefault utför åtgärder i en sekvens och returnerar ett enda resultat. Vissa överlagringar av dessa metoder utlöser ett InvalidOperationException undantag när sekvensen är tom, medan andra överlagringar returnerar null
. Metoden Enumerable.SingleOrDefault genererar också ett InvalidOperationException undantag när sekvensen innehåller mer än ett element.
Kommentar
De flesta metoder som utlöser ett InvalidOperationException undantag är överlagringar. Se till att du förstår beteendet för den överlagring som du väljer.
I följande tabell visas undantagsmeddelanden från undantagsobjekt som InvalidOperationException genereras av anrop till vissa System.Linq.Enumerable metoder.
Metod | Meddelande |
---|---|
Aggregate Average Last Max Min |
Sekvensen innehåller inga element |
First |
Sekvensen innehåller inget matchande element |
Single SingleOrDefault |
Sekvensen innehåller mer än ett matchande element |
Hur du eliminerar eller hanterar undantaget beror på programmets antaganden och på vilken metod du anropar.
När du avsiktligt anropar någon av dessa metoder utan att söka efter en tom sekvens antar du att sekvensen inte är tom och att en tom sekvens är en oväntad förekomst. I det här fallet är det lämpligt att fånga upp eller återväxa undantaget.
Om det inte gick att söka efter en tom sekvens av misstag kan du anropa en av överlagringarna av överbelastningen Enumerable.Any för att avgöra om en sekvens innehåller några element.
Dricks
Enumerable.Any<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) Att anropa metoden innan en sekvens genereras kan förbättra prestandan om de data som ska bearbetas kan innehålla ett stort antal element eller om åtgärden som genererar sekvensen är dyr.
Om du har anropat en metod som Enumerable.First, Enumerable.Lasteller Enumerable.Single, kan du ersätta en alternativ metod, till exempel Enumerable.FirstOrDefault, Enumerable.LastOrDefaulteller Enumerable.SingleOrDefault, som returnerar ett standardvärde i stället för en medlem i sekvensen.
Exemplen innehåller ytterligare information.
I följande exempel används Enumerable.Average metoden för att beräkna medelvärdet för en sekvens vars värden är större än 4. Eftersom inga värden från den ursprungliga matrisen överskrider 4 inkluderas inga värden i sekvensen och metoden genererar ett InvalidOperationException undantag.
using System;
using System.Linq;
public class Example
{
public static void Main()
{
int[] data = { 1, 2, 3, 4 };
var average = data.Where(num => num > 4).Average();
Console.Write("The average of numbers greater than 4 is {0}",
average);
}
}
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException: Sequence contains no elements
// at System.Linq.Enumerable.Average(IEnumerable`1 source)
// at Example.Main()
open System
open System.Linq
let data = [| 1; 2; 3; 4 |]
let average =
data.Where(fun num -> num > 4).Average();
printfn $"The average of numbers greater than 4 is {average}"
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException: Sequence contains no elements
// at System.Linq.Enumerable.Average(IEnumerable`1 source)
// at <StartupCode$fs>.main()
Imports System.Linq
Module Example
Public Sub Main()
Dim data() As Integer = { 1, 2, 3, 4 }
Dim average = data.Where(Function(num) num > 4).Average()
Console.Write("The average of numbers greater than 4 is {0}",
average)
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.InvalidOperationException: Sequence contains no elements
' at System.Linq.Enumerable.Average(IEnumerable`1 source)
' at Example.Main()
Undantaget kan elimineras genom att anropa Any metoden för att avgöra om sekvensen innehåller några element innan metoden som bearbetar sekvensen anropas, vilket visas i följande exempel.
using System;
using System.Linq;
public class EnumerableEx2
{
public static void Main()
{
int[] dbQueryResults = { 1, 2, 3, 4 };
var moreThan4 = dbQueryResults.Where(num => num > 4);
if (moreThan4.Any())
Console.WriteLine("Average value of numbers greater than 4: {0}:",
moreThan4.Average());
else
// handle empty collection
Console.WriteLine("The dataset has no values greater than 4.");
}
}
// The example displays the following output:
// The dataset has no values greater than 4.
open System
open System.Linq
let dbQueryResults = [| 1; 2; 3; 4 |]
let moreThan4 =
dbQueryResults.Where(fun num -> num > 4)
if moreThan4.Any() then
printfn $"Average value of numbers greater than 4: {moreThan4.Average()}:"
else
// handle empty collection
printfn "The dataset has no values greater than 4."
// The example displays the following output:
// The dataset has no values greater than 4.
Imports System.Linq
Module Example1
Public Sub Main()
Dim dbQueryResults() As Integer = {1, 2, 3, 4}
Dim moreThan4 = dbQueryResults.Where(Function(num) num > 4)
If moreThan4.Any() Then
Console.WriteLine("Average value of numbers greater than 4: {0}:",
moreThan4.Average())
Else
' Handle empty collection.
Console.WriteLine("The dataset has no values greater than 4.")
End If
End Sub
End Module
' The example displays the following output:
' The dataset has no values greater than 4.
Metoden Enumerable.First returnerar det första objektet i en sekvens eller det första elementet i en sekvens som uppfyller ett angivet villkor. Om sekvensen är tom och därför inte har något första element genererar den ett InvalidOperationException undantag.
I följande exempel Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) genererar metoden ett InvalidOperationException undantag eftersom matrisen dbQueryResults inte innehåller ett element som är större än 4.
using System;
using System.Linq;
public class EnumerableEx3
{
public static void Main()
{
int[] dbQueryResults = { 1, 2, 3, 4 };
var firstNum = dbQueryResults.First(n => n > 4);
Console.WriteLine("The first value greater than 4 is {0}",
firstNum);
}
}
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains no matching element
// at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
// at Example.Main()
open System
open System.Linq
let dbQueryResults = [| 1; 2; 3; 4 |]
let firstNum = dbQueryResults.First(fun n -> n > 4)
printfn $"The first value greater than 4 is {firstNum}"
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains no matching element
// at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
// at <StartupCode$fs>.main()
Imports System.Linq
Module Example2
Public Sub Main()
Dim dbQueryResults() As Integer = {1, 2, 3, 4}
Dim firstNum = dbQueryResults.First(Function(n) n > 4)
Console.WriteLine("The first value greater than 4 is {0}",
firstNum)
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.InvalidOperationException:
' Sequence contains no matching element
' at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
' at Example.Main()
Du kan anropa Enumerable.FirstOrDefault metoden i stället för Enumerable.First att returnera ett angivet eller standardvärde. Om metoden inte hittar ett första element i sekvensen returneras standardvärdet för den datatypen. Standardvärdet är null
för en referenstyp, noll för en numerisk datatyp och DateTime.MinValue för DateTime typen.
Kommentar
Att tolka det värde som returneras av Enumerable.FirstOrDefault metoden kompliceras ofta av att standardvärdet för typen kan vara ett giltigt värde i sekvensen. I det här fallet anropar Enumerable.Any du metoden för att avgöra om sekvensen har giltiga medlemmar innan du Enumerable.First anropar metoden.
I följande exempel anropas Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) metoden för att förhindra att undantaget InvalidOperationException utlöses i föregående exempel.
using System;
using System.Linq;
public class EnumerableEx4
{
public static void Main()
{
int[] dbQueryResults = { 1, 2, 3, 4 };
var firstNum = dbQueryResults.FirstOrDefault(n => n > 4);
if (firstNum == 0)
Console.WriteLine("No value is greater than 4.");
else
Console.WriteLine("The first value greater than 4 is {0}",
firstNum);
}
}
// The example displays the following output:
// No value is greater than 4.
open System
open System.Linq
let dbQueryResults = [| 1; 2; 3; 4 |]
let firstNum = dbQueryResults.FirstOrDefault(fun n -> n > 4)
if firstNum = 0 then
printfn "No value is greater than 4."
else
printfn $"The first value greater than 4 is {firstNum}"
// The example displays the following output:
// No value is greater than 4.
Imports System.Linq
Module Example3
Public Sub Main()
Dim dbQueryResults() As Integer = {1, 2, 3, 4}
Dim firstNum = dbQueryResults.FirstOrDefault(Function(n) n > 4)
If firstNum = 0 Then
Console.WriteLine("No value is greater than 4.")
Else
Console.WriteLine("The first value greater than 4 is {0}",
firstNum)
End If
End Sub
End Module
' The example displays the following output:
' No value is greater than 4.
Anropa Enumerable.Single eller Enumerable.SingleOrDefault på en sekvens utan ett element
Metoden Enumerable.Single returnerar det enda elementet i en sekvens, eller det enda elementet i en sekvens som uppfyller ett angivet villkor. Om det inte finns några element i sekvensen, eller om det finns fler än ett element, utlöser metoden ett InvalidOperationException undantag.
Du kan använda Enumerable.SingleOrDefault metoden för att returnera ett standardvärde i stället för att utlösa ett undantag när sekvensen inte innehåller några element. Metoden genererar dock Enumerable.SingleOrDefault fortfarande ett InvalidOperationException undantag när sekvensen innehåller mer än ett element.
I följande tabell visas undantagsmeddelanden från undantagsobjekt som InvalidOperationException genereras av anrop till Enumerable.Single metoderna och Enumerable.SingleOrDefault .
Metod | Meddelande |
---|---|
Single |
Sekvensen innehåller inget matchande element |
Single SingleOrDefault |
Sekvensen innehåller mer än ett matchande element |
I följande exempel utlöser anropet Enumerable.Single till metoden ett InvalidOperationException undantag eftersom sekvensen inte har ett element större än 4.
using System;
using System.Linq;
public class EnumerableEx5
{
public static void Main()
{
int[] dbQueryResults = { 1, 2, 3, 4 };
var singleObject = dbQueryResults.Single(value => value > 4);
// Display results.
Console.WriteLine("{0} is the only value greater than 4", singleObject);
}
}
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains no matching element
// at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
// at Example.Main()
open System
open System.Linq
let dbQueryResults = [| 1; 2; 3; 4 |]
let singleObject = dbQueryResults.Single(fun value -> value > 4)
// Display results.
printfn $"{singleObject} is the only value greater than 4"
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains no matching element
// at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
// at <StartupCode$fs>.main()
Imports System.Linq
Module Example4
Public Sub Main()
Dim dbQueryResults() As Integer = {1, 2, 3, 4}
Dim singleObject = dbQueryResults.Single(Function(value) value > 4)
' Display results.
Console.WriteLine("{0} is the only value greater than 4",
singleObject)
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.InvalidOperationException:
' Sequence contains no matching element
' at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
' at Example.Main()
I följande exempel försöker man förhindra InvalidOperationException att undantaget utlöses när en sekvens är tom genom att i stället anropa Enumerable.SingleOrDefault metoden. Men eftersom den här sekvensen returnerar flera element vars värde är större än 2, utlöser den också ett InvalidOperationException undantag.
using System;
using System.Linq;
public class EnumerableEx6
{
public static void Main()
{
int[] dbQueryResults = { 1, 2, 3, 4 };
var singleObject = dbQueryResults.SingleOrDefault(value => value > 2);
if (singleObject != 0)
Console.WriteLine("{0} is the only value greater than 2",
singleObject);
else
// Handle an empty collection.
Console.WriteLine("No value is greater than 2");
}
}
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains more than one matching element
// at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
// at Example.Main()
open System
open System.Linq
let dbQueryResults = [| 1; 2; 3; 4 |]
let singleObject = dbQueryResults.SingleOrDefault(fun value -> value > 2)
if singleObject <> 0 then
printfn $"{singleObject} is the only value greater than 2"
else
// Handle an empty collection.
printfn "No value is greater than 2"
// The example displays the following output:
// Unhandled Exception: System.InvalidOperationException:
// Sequence contains more than one matching element
// at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
// at <StartupCode$fs>.main()
Imports System.Linq
Module Example5
Public Sub Main()
Dim dbQueryResults() As Integer = {1, 2, 3, 4}
Dim singleObject = dbQueryResults.SingleOrDefault(Function(value) value > 2)
If singleObject <> 0 Then
Console.WriteLine("{0} is the only value greater than 2",
singleObject)
Else
' Handle an empty collection.
Console.WriteLine("No value is greater than 2")
End If
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.InvalidOperationException:
' Sequence contains more than one matching element
' at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
' at Example.Main()
Enumerable.Single Att anropa metoden förutsätter att antingen en sekvens eller den sekvens som uppfyller angivna villkor endast innehåller ett element. Enumerable.SingleOrDefault förutsätter en sekvens med noll eller ett resultat, men inte mer. Om det här antagandet är avsiktligt från din sida och dessa villkor inte uppfylls är det lämpligt att återväxta eller fånga resultatet InvalidOperationException . Annars, eller om du förväntar dig att ogiltiga villkor kommer att inträffa med viss frekvens, bör du överväga att använda någon annan Enumerable metod, till exempel FirstOrDefault eller Where.
Dynamisk fältåtkomst mellan programdomäner
OpCodes.Ldflda CIL-instruktionen (Common Intermediate Language) utlöser ett InvalidOperationException undantag om objektet som innehåller fältet vars adress du försöker hämta inte finns i programdomänen där koden körs. Adressen för ett fält kan bara nås från programdomänen där det finns.
Utlösa ett InvalidOperationException-undantag
Du bör bara utlösa ett InvalidOperationException undantag när objektets tillstånd av någon anledning inte stöder ett visst metodanrop. Det vill säga att metodanropet är giltigt under vissa omständigheter eller kontexter, men är ogiltigt i andra.
Om metodens anropsfel beror på ogiltiga argument ska ArgumentException en av dess härledda klasser, ArgumentNullException eller ArgumentOutOfRangeException, genereras i stället.