InvalidOperationException 类

定义

当方法调用对于对象的当前状态无效时引发的异常。

public ref class InvalidOperationException : Exception
public ref class InvalidOperationException : SystemException
public class InvalidOperationException : Exception
public class InvalidOperationException : SystemException
[System.Serializable]
public class InvalidOperationException : SystemException
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class InvalidOperationException : SystemException
type InvalidOperationException = class
    inherit Exception
type InvalidOperationException = class
    inherit SystemException
[<System.Serializable>]
type InvalidOperationException = class
    inherit SystemException
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type InvalidOperationException = class
    inherit SystemException
Public Class InvalidOperationException
Inherits Exception
Public Class InvalidOperationException
Inherits SystemException
继承
InvalidOperationException
继承
InvalidOperationException
派生
属性

注解

InvalidOperationException 在调用方法失败的原因是参数无效的原因导致的情况下使用。 通常,当对象的状态不支持方法调用时,会引发它。 例如, InvalidOperationException 异常由以下方法引发:

重要

InvalidOperationException由于异常可以在各种情况下引发,因此必须读取属性返回的Message异常消息。

本部分内容:

InvalidOperationException 异常的一些常见原因
从非 UI 线程更新 UI 线程
循环访问集合时更改集合
对无法比较其对象的数组或集合进行排序
将可为 Null<的 T> 强制转换为其基础类型
对空集合调用 System.Linq.Enumerable 方法
在没有一个元素的序列上调用 Enumerable.Single 或 Enumerable.SingleOrDefault
动态跨应用程序域域访问
引发 InvalidOperationException 异常
其他信息

InvalidOperationException 异常的一些常见原因

以下部分介绍了如何在应用中引发异常的一些常见情况 InvalidOperationException 。 如何处理该问题取决于具体情况。 但是,大多数情况下,开发人员错误导致异常, InvalidOperationException 并且可以期待并避免异常。

从非 UI 线程更新 UI 线程

通常,工作线程用于执行一些后台工作,这些工作涉及收集数据以显示在应用程序的用户界面中。 但是, 大多数 GUI (.NET 的图形用户界面) 应用程序框架(如 Windows 窗体 和 Windows Presentation Foundation (WPF) ),仅允许从创建 (和管理主线程或 UI 线程) 的线程访问 GUI 对象。 尝试从 UI 线程以外的线程访问 UI 元素时,将引发一 InvalidOperationException 个。 下表显示了异常消息的文本。

应用程序类型 Message
WPF 应用 调用线程无法访问此对象,因为它属于其他线程所有。
UWP 应用 应用程序调用了为其他线程封送的接口。
Windows 窗体应用 跨线程操作无效:控制从创建线程以外的线程访问的“TextBox1”。

.NET 的 UI 框架实现 调度程序 模式,该模式包含一种方法,用于检查对 UI 元素成员的调用是否正在 UI 线程上执行,以及用于计划对 UI 线程的调用的其他方法:

  • 在 WPF 应用中,调用 Dispatcher.CheckAccess 该方法以确定方法是否在非 UI 线程上运行。 如果方法在 UI 线程false上运行,则返回true此方法。 调用方法的 Dispatcher.Invoke 重载之一,以计划 UI 线程上的调用。

  • 在 UWP 应用中,检查 CoreDispatcher.HasThreadAccess 属性以确定方法是否在非 UI 线程上运行。 CoreDispatcher.RunAsync调用该方法以执行更新 UI 线程的委托。

  • 在Windows 窗体应用中,使用Control.InvokeRequired属性来确定方法是否在非 UI 线程上运行。 调用方法的 Control.Invoke 重载之一以执行更新 UI 线程的委托。

以下示例演示 InvalidOperationException 了尝试从创建 UI 的线程以外的线程更新 UI 元素时引发的异常。 每个示例都需要创建两个控件:

  • A text box control named textBox1. 在Windows 窗体应用中,应将其Multiline属性设置为 true

  • 名为 的 threadExampleBtn按钮控件。 该示例为按钮Click的事件提供处理程序ThreadsExampleBtn_Click

在每个情况下, threadExampleBtn_Click 事件处理程序都会调用该方法 DoSomeWork 两次。 第一个调用以同步方式运行并成功。 但是第二次调用,因为它以异步方式在线程池线程上运行,因此会尝试从非 UI 线程更新 UI。 这会导致 InvalidOperationException 异常。

WPF 和 UWP 应用

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;
}
Private Async Sub threadExampleBtn_Click(sender As Object, e As RoutedEventArgs) Handles threadExampleBtn.Click
    textBox1.Text = String.Empty

    textBox1.Text = "Simulating work on UI thread." + vbCrLf
    DoSomeWork(20)
    textBox1.Text += "Work completed..." + vbCrLf

    textBox1.Text += "Simulating work on non-UI thread." + vbCrLf
    Await Task.Factory.StartNew(Sub()
                                    DoSomeWork(1000)
                                End Sub)
    textBox1.Text += "Work completed..." + vbCrLf
End Sub

Private Async Sub DoSomeWork(milliseconds As Integer)
    ' Simulate work.
    Await Task.Delay(milliseconds)

    ' Report completion.
    Dim msg = String.Format("Some work completed in {0} ms.", milliseconds) + vbCrLf
    textBox1.Text += msg
End Sub

以下版本的 DoSomeWork 方法消除了 WPF 应用中的异常。

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; });
}
Private Async Sub DoSomeWork(milliseconds As Integer)
    ' Simulate work.
    Await Task.Delay(milliseconds)

    ' Report completion.
    Dim uiAccess As Boolean = textBox1.Dispatcher.CheckAccess()
    Dim msg As String = String.Format("Some work completed in {0} ms. on {1}UI thread",
                                      milliseconds, If(uiAccess, String.Empty, "non-")) + 
                                      vbCrLf 
    If uiAccess Then
        textBox1.Text += msg
    Else
        textBox1.Dispatcher.Invoke( Sub() textBox1.Text += msg)
    End If
End Sub

以下版本的 DoSomeWork 方法消除了 UWP 应用中的异常。

private async void DoSomeWork(int milliseconds)
{
    // Simulate work.
    await Task.Delay(milliseconds);

    // Report completion.
    bool uiAccess = textBox1.Dispatcher.HasThreadAccess;
    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
        await textBox1.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { textBox1.Text += msg; });
}
Private Async Sub DoSomeWork(milliseconds As Integer)
    ' Simulate work.
    Await Task.Delay(milliseconds)

    ' Report completion.
    Dim uiAccess As Boolean = textBox1.Dispatcher.HasThreadAccess
    Dim msg As String = String.Format("Some work completed in {0} ms. on {1}UI thread" + vbCrLf,
                                      milliseconds, If(uiAccess, String.Empty, "non-"))
    If (uiAccess) Then
        textBox1.Text += msg
    Else
        Await textBox1.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() textBox1.Text += msg)
    End If
End Sub

Windows 窗体应用

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 threadExampleBtn.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

以下版本的DoSomeWork方法消除了Windows 窗体应用中的异常。

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

循环访问集合时更改集合

foreach C# For Each 中的语句、 for...in Visual Basic中的语句用于循环访问集合的成员以及读取或修改其各个元素。 但是,它不能用于添加或删除集合中的项。 执行此操作会引发异常InvalidOperationException,其中包含类似于“集合已修改”的消息;枚举操作可能无法执行。

以下示例循环访问整数集合,尝试将每个整数的平方添加到集合中。 该示例引发对该方法的第一次 InvalidOperationException 调用 List<T>.Add

using System;
using System.Collections.Generic;

public class Example
{
   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 Example
   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()

可以通过以下两种方式之一消除异常,具体取决于应用程序逻辑:

  • 如果在循环访问元素时必须将其添加到集合中,则可以使用 for F#) 语句中的 (for..to (而不是 foreachfor...inFor Each索引来循环访问它。 以下示例使用 for 语句将集合中的数字平方添加到集合中。

    using System;
    using System.Collections.Generic;
    
    public class Example
    {
       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 Example
       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
    

    请注意,必须在循环中使用循环内的计数器来循环访问集合之前,必须建立迭代次数,该计数器将通过循环向后迭代、从 Count - 1 到 0 循环,或如示例所示,将数组中的元素数分配给变量,并使用它建立循环的上限。 否则,如果在每次迭代时将元素添加到集合中,将产生无限循环结果。

  • 如果不需要在循环访问集合时将元素添加到集合中,则可以将元素存储在循环访问集合完成后添加的临时集合中。 以下示例使用此方法将集合中的数字平方添加到临时集合中,然后将集合合并为单个数组对象。

    using System;
    using System.Collections.Generic;
    
    public class Example
    {
       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 Example
       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
    

对无法比较其对象的数组或集合进行排序

常规用途排序方法(如 Array.Sort(Array) 方法或 List<T>.Sort() 方法)通常需要至少对某个对象进行排序来实现 IComparable<T>IComparable 接口。 如果没有,则无法对集合或数组进行排序,并且该方法会引发异常 InvalidOperationException 。 以下示例定义一个类,将两PersonPerson对象存储在泛型List<T>对象中,并尝试对它们进行排序。 如示例中的输出所示,对方法的 List<T>.Sort() 调用将引发一个 InvalidOperationException

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 Example
{
   public static void Main()
   {
      var people = new List<Person>();

      people.Add(new Person("John", "Doe"));
      people.Add(new Person("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 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
End Class

Module Example
   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:
'    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()

可以通过以下三种方式之一消除异常:

  • 如果可以拥有尝试对 (进行排序的类型,即,如果控制其源代码) ,则可以对其进行修改以实现 IComparable<T>IComparable 接口。 这要求实现 IComparable<T>.CompareToCompareTo 方法。 向现有类型添加接口实现不是中断性变更。

    以下示例使用此方法为Person类提供IComparable<T>实现。 你仍然可以调用集合或数组的常规排序方法,并且,如示例所示的输出,集合成功排序。

    using System;
    using System.Collections.Generic;
    
    public class Person : IComparable<Person>
    {
       public Person(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 Example
    {
       public static void Main()
       {
          var people = new List<Person>();
    
          people.Add(new Person("John", "Doe"));
          people.Add(new Person("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 Example
       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
    
  • 如果无法修改尝试排序的类型的源代码,则可以定义实现 IComparer<T> 接口的特殊用途排序类。 可以调用包含IComparer<T>参数的方法的Sort重载。 如果要开发可以基于多个条件对对象进行排序的专用排序类,此方法特别有用。

    以下示例通过开发用于对集合进行排序Person的自定义PersonComparer类来使用此方法。 然后,它将此类的实例传递给 List<T>.Sort(IComparer<T>) 该方法。

    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 PersonComparer : IComparer<Person>
    {
       public int Compare(Person x, Person y)
       {
          return String.Format("{0} {1}", x.LastName, x.FirstName).
                 CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName));
       }
    }
    
    public class Example
    {
       public static void Main()
       {
          var people = new List<Person>();
    
          people.Add(new Person("John", "Doe"));
          people.Add(new Person("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 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
    End Class
    
    Public Class PersonComparer : Implements IComparer(Of Person)
       Public Function Compare(x As Person, y As Person) As Integer _
              Implements IComparer(Of Person).Compare
          Return String.Format("{0} {1}", x.LastName, x.FirstName).
                 CompareTo(String.Format("{0} {1}", y.LastName, y.FirstName))    
       End Function       
    End Class
    
    Module Example
       Public Sub Main()
          Dim people As New List(Of Person)()
          
          people.Add(New Person("John", "Doe"))
          people.Add(New Person("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
    
  • 如果无法修改尝试排序的类型的源代码,则可以创建委托 Comparison<T> 来执行排序。 委托签名为

    Function Comparison(Of T)(x As T, y As T) As Integer  
    
    int Comparison<T>(T x, T y)  
    

    以下示例通过定义 PersonComparison 与委托签名匹配 Comparison<T> 的方法来使用此方法。 然后,它将此委托传递给 List<T>.Sort(Comparison<T>) 方法。

    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 Example
    {
       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 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
    End Class
    
    Module Example
       Public Sub Main()
          Dim people As New List(Of Person)()
          
          people.Add(New Person("John", "Doe"))
          people.Add(New Person("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 Person, y As Person) 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
    

将可为 Null 的可为 Null<T> 强制转换为其基础类型

尝试强制转换 Nullable<T> 其基础类型的值 nullInvalidOperationException 引发异常并显示错误消息“可为 Null 的对象必须具有值。

以下示例尝试循环访问包含Nullable(Of Integer)值的数组时引发InvalidOperationException异常。

using System;
using System.Linq;

public class Example
{
   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 Example
   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()

若要防止异常:

以下示例同时执行这两项操作以避免 InvalidOperationException 异常。

using System;
using System.Linq;

public class Example
{
   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 Example
   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

对空集合调用 System.Linq.Enumerable 方法

Enumerable.AggregateEnumerable.AverageEnumerable.FirstEnumerable.LastEnumerable.MaxEnumerable.MinEnumerable.SingleEnumerable.SingleOrDefault方法对序列执行操作并返回单个结果。 当序列为空时,这些方法的某些重载会引发 InvalidOperationException 异常,而其他重载则返回 null。 当序列包含多个元素时,该方法 Enumerable.SingleOrDefault 也会引发 InvalidOperationException 异常。

备注

引发 InvalidOperationException 异常的大多数方法是重载。 请确保了解所选重载的行为。

下表列出了调用某些System.Linq.Enumerable方法引发的异常对象中的异常消息InvalidOperationException

方法 Message
Aggregate
Average
Last
Max
Min
序列不包含任何元素
First 序列不包含匹配元素
Single
SingleOrDefault
序列包含多个匹配元素

如何消除或处理异常取决于应用程序的假设和调用的特定方法。

这些示例提供了更多详细信息。

以下示例使用 Enumerable.Average 该方法计算其值大于 4 的序列的平均值。 由于原始数组的值不超过 4,序列中不包含任何值,并且该方法将引发异常 InvalidOperationException

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()

通过调用 Any 方法来确定序列是否包含任何元素,然后调用处理序列的方法之前,可以消除异常,如以下示例所示。

using System;
using System.Linq;

public class Example
{
   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 Example
   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.

该方法 Enumerable.First 返回序列中的第一项或满足指定条件的序列中的第一个元素。 如果序列为空,因此没有第一个元素,则会引发 InvalidOperationException 异常。

在下面的示例中,该方法 Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) 会引发异常 InvalidOperationException ,因为 dbQueryResults 数组不包含大于 4 的元素。

using System;
using System.Linq;

public class Example
{
   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 Example
   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()

可以调用 Enumerable.FirstOrDefault 该方法, Enumerable.First 而不是返回指定的或默认值。 如果该方法在序列中找不到第一个元素,则返回该数据类型的默认值。 默认值为 null 引用类型,数值数据类型为零,类型 DateTime.MinValueDateTime 零。

备注

解释方法返回 Enumerable.FirstOrDefault 的值通常很复杂,因为类型默认值可以是序列中的有效值。 在这种情况下,调用 Enumerable.Any 方法以确定序列在调用 Enumerable.First 该方法之前是否具有有效成员。

以下示例调用该方法 Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) 以防止 InvalidOperationException 上一示例中引发的异常。

using System;
using System.Linq;

public class Example
{
   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 Example
   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.

在没有一个元素的序列上调用 Enumerable.Single 或 Enumerable.SingleOrDefault

该方法 Enumerable.Single 返回序列的唯一元素,或满足指定条件的序列的唯一元素。 如果序列中没有元素,或者如果有多个元素,该方法将引发异常 InvalidOperationException

可以使用 Enumerable.SingleOrDefault 该方法返回默认值,而不是在序列不包含任何元素时引发异常。 但是,当序列包含多个元素时,该方法 Enumerable.SingleOrDefault 仍会引发 InvalidOperationException 异常。

下表列出了调用Enumerable.SingleEnumerable.SingleOrDefault方法引发的异常对象中的异常消息InvalidOperationException

方法 Message
Single 序列不包含匹配元素
Single
SingleOrDefault
序列包含多个匹配元素

在下面的示例中,对方法的 Enumerable.Single 调用将引发异常 InvalidOperationException ,因为序列没有大于 4 的元素。

using System;
using System.Linq;

public class Example
{
   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 Example
   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()

以下示例尝试通过调用方法来防止 InvalidOperationException 序列为空时引发的 Enumerable.SingleOrDefault 异常。 但是,由于此序列返回的值大于 2 的多个元素,因此也会引发异常 InvalidOperationException

using System;
using System.Linq;

public class Example
{
   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 Example
   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调用该方法假定序列或满足指定条件的序列仅包含一个元素。 Enumerable.SingleOrDefault 假定序列包含零个或一个结果,但不再包含。 如果此假设是你部分的故意假设,并且不符合这些条件,则重新引发或捕获结果 InvalidOperationException 是适当的。 否则,或者如果预期某些频率会出现无效条件,应考虑使用其他 Enumerable 方法,例如 FirstOrDefaultWhere

动态跨应用程序域字段访问

OpCodes.Ldflda Microsoft 中间语言 (MSIL) 指令在包含您尝试检索其地址的字段的对象不在执行代码的应用程序域中时引发InvalidOperationException异常。 只能从它所在的应用程序域中访问字段的地址。

引发 InvalidOperationException 异常

仅当对象的状态出于某种原因不支持特定方法调用时,才应引发 InvalidOperationException 异常。 也就是说,方法调用在某些情况下或上下文中有效,但在其他情况下无效。

如果方法调用失败是由于参数无效,则 ArgumentException 应改为引发其派生类 ArgumentNullException ArgumentOutOfRangeException之一或其中一个。

其他信息

InvalidOperationException 使用具有值0x80131509的 HRESULT COR_E_INVALIDOPERATION。

有关实例的初始属性值的列表InvalidOperationException,请参阅InvalidOperationException构造函数。

构造函数

InvalidOperationException()

初始化 InvalidOperationException 类的新实例。

InvalidOperationException(SerializationInfo, StreamingContext)

用序列化数据初始化 InvalidOperationException 类的新实例。

InvalidOperationException(String)

用指定的错误消息初始化 InvalidOperationException 类的新实例。

InvalidOperationException(String, Exception)

使用指定的错误消息和对作为此异常原因的内部异常的引用来初始化 InvalidOperationException 类的新实例。

属性

Data

获取键/值对的集合,这些键/值对提供有关该异常的其他用户定义信息。

(继承自 Exception)
HelpLink

获取或设置指向与此异常关联的帮助文件链接。

(继承自 Exception)
HResult

获取或设置 HRESULT(一个分配给特定异常的编码数字值)。

(继承自 Exception)
InnerException

获取导致当前异常的 Exception 实例。

(继承自 Exception)
Message

获取描述当前异常的消息。

(继承自 Exception)
Source

获取或设置导致错误的应用程序或对象的名称。

(继承自 Exception)
StackTrace

获取调用堆栈上的即时框架字符串表示形式。

(继承自 Exception)
TargetSite

获取引发当前异常的方法。

(继承自 Exception)

方法

Equals(Object)

确定指定对象是否等于当前对象。

(继承自 Object)
GetBaseException()

当在派生类中重写时,返回 Exception,它是一个或多个并发的异常的根本原因。

(继承自 Exception)
GetHashCode()

作为默认哈希函数。

(继承自 Object)
GetObjectData(SerializationInfo, StreamingContext)

当在派生类中重写时,用关于异常的信息设置 SerializationInfo

(继承自 Exception)
GetType()

获取当前实例的运行时类型。

(继承自 Exception)
MemberwiseClone()

创建当前 Object 的浅表副本。

(继承自 Object)
ToString()

创建并返回当前异常的字符串表示形式。

(继承自 Exception)

事件

SerializeObjectState
已过时。

当异常被序列化用来创建包含有关该异常的徐列出数据的异常状态对象时会出现该问题。

(继承自 Exception)

适用于

另请参阅