Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.
InvalidOperationException se usa en los casos en los que el error al invocar un método se debe a motivos distintos de argumentos no válidos. Normalmente, se produce cuando el estado de un objeto no puede admitir la llamada al método. Por ejemplo, se produce una InvalidOperationException excepción mediante métodos como:
- IEnumerator.MoveNext si los objetos de una colección se modifican después de crear el enumerador. Para más información, vea Cambio de una colección mientras se itera por ella.
- ResourceSet.GetString si el conjunto de recursos se cierra antes de que se realice la llamada al método.
- XContainer.Add, si el objeto o los objetos que se van a agregar darían como resultado un documento XML estructurado incorrectamente.
- Método que intenta manipular la interfaz de usuario desde un subproceso que no es el subproceso principal o de la interfaz de usuario.
Importante
Dado que la InvalidOperationException excepción se puede producir en una amplia variedad de circunstancias, es importante leer el mensaje de excepción devuelto por la Message propiedad .
InvalidOperationException usa HRESULT COR_E_INVALIDOPERATION
, que tiene el valor 0x80131509.
Para obtener una lista de valores de propiedad iniciales para una instancia de InvalidOperationException, vea los InvalidOperationException constructores.
Causas comunes de excepciones InvalidOperationException
En las secciones siguientes se muestra cómo se producen algunos casos comunes en los que se produce una InvalidOperationException excepción en una aplicación. La forma de controlar el problema depende de la situación específica. Sin embargo, más comúnmente, la excepción se debe a un error del desarrollador y la InvalidOperationException excepción se puede anticipar y evitar.
Actualización de un subproceso de interfaz de usuario desde un subproceso que no es de interfaz de usuario
A menudo, los subprocesos de trabajo se usan para realizar algún trabajo en segundo plano que implica recopilar datos que se mostrarán en la interfaz de usuario de una aplicación. Sin embargo, la mayoría de los marcos de aplicación de la interfaz gráfica de usuario (GUI) para .NET, como Windows Forms y Windows Presentation Foundation (WPF), permiten acceder a objetos de GUI solo desde el subproceso que crea y administra la interfaz de usuario (el subproceso principal o de interfaz de usuario). Si trata de acceder a un elemento de la interfaz de usuario desde un subproceso que no es el subproceso de la interfaz de usuario, se inicia una excepción InvalidOperationException. El texto del mensaje de excepción se muestra en la tabla siguiente.
Tipo de aplicación | Mensaje |
---|---|
Aplicación WPF | El subproceso que llama no puede tener acceso a este objeto porque un subproceso diferente lo posee. |
Aplicación para UWP | La aplicación ha llamado a una interfaz serializada para un subproceso diferente. |
Aplicación de Windows Forms | Operación entre subprocesos no válida: control 'TextBox1' al que se accede desde un subproceso distinto del subproceso en el que se creó. |
Los marcos de interfaz de usuario para .NET implementan un patrón de distribuidor que incluye un método para comprobar si se ejecuta una llamada a un miembro de un elemento de interfaz de usuario en el subproceso de la interfaz de usuario y otros métodos para programar la llamada en el subproceso de interfaz de usuario:
- En las aplicaciones de WPF, llame al Dispatcher.CheckAccess método para determinar si un método se ejecuta en un subproceso que no es de interfaz de usuario. Devuelve
true
si el método se ejecuta en el subproceso de la interfaz de usuario yfalse
de lo contrario. Llame a una de las sobrecargas del método Dispatcher.Invoke para programar la llamada en el subproceso de la interfaz de usuario. - En las aplicaciones para UWP, compruebe la CoreDispatcher.HasThreadAccess propiedad para determinar si un método se ejecuta en un subproceso que no es de interfaz de usuario. Llame al método CoreDispatcher.RunAsync para ejecutar un delegado que actualice el subproceso de la interfaz de usuario.
- En las aplicaciones de Windows Forms, use la Control.InvokeRequired propiedad para determinar si un método se ejecuta en un subproceso que no es de interfaz de usuario. Llame a una de las sobrecargas del método Control.Invoke para ejecutar un delegado que actualice el subproceso de interfaz de usuario.
En los ejemplos siguientes se muestra la InvalidOperationException excepción que se produce al intentar actualizar un elemento de interfaz de usuario desde un subproceso distinto del subproceso que lo creó. Cada ejemplo requiere que cree dos controles:
- Control de cuadro de texto denominado
textBox1
. En una aplicación de Windows Forms, debe establecer su propiedad Multiline entrue
. - Control de botón denominado
threadExampleBtn
. En el ejemplo se proporciona un controlador,ThreadsExampleBtn_Click
, para el evento delClick
botón.
En cada caso, el threadExampleBtn_Click
controlador de eventos llama al DoSomeWork
método dos veces. La primera llamada se ejecuta sincrónicamente y se realiza correctamente. Pero la segunda llamada, como se ejecuta de forma asincrónica en un subproceso de grupo de subprocesos, intenta actualizar la interfaz de usuario desde un subproceso que no es de interfaz de usuario. Esto da como resultado una InvalidOperationException excepción.
Aplicaciones de WPF
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;
}
La siguiente versión del DoSomeWork
método elimina la excepción en una aplicación 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; });
}
Aplicaciones de Windows Forms
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
La siguiente versión del DoSomeWork
método elimina la excepción en una aplicación de Windows Forms.
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
Cambio de una colección mientras se itera por ella
La instrucción foreach
de C#, for...in
en F#, o la instrucción For Each
de Visual Basic se usa para iterar por los miembros de una colección y leer o modificar sus elementos individuales. Sin embargo, no se puede usar para agregar o quitar elementos de la colección. Al hacerlo, se produce una InvalidOperationException excepción con un mensaje similar al siguiente: "Se modificó la colección; es posible que la operación de enumeración no se ejecute".
En el ejemplo siguiente se itera por una colección de enteros que intenta agregar el cuadrado de cada entero a la colección. En el ejemplo se inicia una excepción InvalidOperationException con la primera llamada al método List<T>.Add.
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($"{number}^{square}");
Console.WriteLine($"Adding {square} to the collection...");
Console.WriteLine();
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()
Puede eliminar la excepción de una de estas dos maneras, en función de la lógica de la aplicación:
Si se deben agregar elementos a la colección mientras se recorre en iteración, puede hacerlo por índice mediante la instrucción
for
(for..to
en F#) en lugar deforeach
,for...in
oFor Each
. En el ejemplo siguiente se usa la instrucción for para agregar el cuadrado de números de la colección a la colección.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($"{numbers[ctr]}^{square}"); Console.WriteLine($"Adding {square} to the collection..."); Console.WriteLine(); 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
Tenga en cuenta que debe establecer el número de iteraciones antes de iterar la colección mediante un contador dentro del bucle que salga adecuadamente del bucle, iterando hacia atrás, de
Count
- 1 a 0 o, como hace el ejemplo, asignando el número de elementos de la matriz a una variable y usándolo para establecer el límite superior del bucle. De lo contrario, si se agrega un elemento a la colección en cada iteración, se produce un bucle sin fin.Si no es necesario agregar elementos a la colección mientras se itera, puede almacenar los elementos que se van a agregar en una colección temporal y añadirlos después de que se haya completado la iteración de la colección. En el ejemplo siguiente se usa este enfoque para agregar el cuadrado de números de una colección a una colección temporal y, a continuación, para combinar las colecciones en un único objeto de matriz.
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
Ordenar una matriz o colección cuyos objetos no se pueden comparar
Los métodos de ordenación de uso general, como el Array.Sort(Array) método o el List<T>.Sort() método, suelen requerir que al menos uno de los objetos que se ordenen implemente la IComparable<T> interfaz o IComparable . Si no es así, la colección o matriz no se puede ordenar y el método produce una InvalidOperationException excepción. En el ejemplo siguiente se define una Person
clase, se almacenan dos Person
objetos en un objeto genérico List<T> y se intenta ordenarlos. Como se muestra en la salida del ejemplo, la llamada al método List<T>.Sort() inicia una excepción 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($"{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()
Puede eliminar la excepción de cualquiera de estas tres maneras:
Si puede poseer el tipo que está intentando ordenar (es decir, si controla su código fuente), puede modificarlo para implementar la interfaz IComparable<T> o la interfaz IComparable. Esto requiere que implemente el método IComparable<T>.CompareTo o el método CompareTo. Agregar una implementación de interfaz a un tipo existente no es un cambio importante.
En el ejemplo siguiente se usa este enfoque para proporcionar una IComparable<T> implementación para la
Person
clase . Todavía puede llamar al método de ordenación general de la colección o matriz y, como se muestra en la salida del ejemplo, la colección se ordena correctamente.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($"{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
Si no puede modificar el código fuente del tipo que intenta ordenar, puede definir una clase de ordenación de propósito especial que implemente la IComparer<T> interfaz. Puede llamar a una sobrecarga del método
Sort
que incluye un parámetro IComparer<T>. Este enfoque es especialmente útil si desea desarrollar una clase de ordenación especializada que pueda ordenar objetos en función de varios criterios.En el ejemplo siguiente se usa el enfoque mediante el desarrollo de una clase personalizada
PersonComparer
que se usa para ordenarPerson
colecciones. A continuación, pasa una instancia de esta clase al List<T>.Sort(IComparer<T>) método .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($"{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
Si no puede modificar el código fuente del tipo que intenta ordenar, puede crear un Comparison<T> delegado para realizar la ordenación. La firma del delegado es
Function Comparison(Of T)(x As T, y As T) As Integer
int Comparison<T>(T x, T y)
En el ejemplo siguiente se usa el enfoque definiendo un
PersonComparison
método que coincida con la Comparison<T> firma del delegado. Después, pasa este delegado al método 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 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($"{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
Conversión de <T> que admite un valor NULL y que es NULL a su tipo subyacente
Al intentar convertir un valor Nullable<T> que es null
a su tipo subyacente, se inicia una excepción InvalidOperationException y se muestra el mensaje de error "El objeto que admite un valor NULL debe tener un valor.
En el ejemplo siguiente se inicia una excepción InvalidOperationException cuando intenta iterar por una matriz que incluye un valor Nullable(Of Integer)
.
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()
Para evitar la excepción:
- Use la Nullable<T>.HasValue propiedad para seleccionar solo los elementos que no son
null
. - Llame a una de las sobrecargas de Nullable<T>.GetValueOrDefault a fin de proporcionar un valor predeterminado para un valor
null
.
En el ejemplo siguiente se usan las dos opciones para evitar la excepción 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
Llamada a un método System.Linq.Enumerable en una colección vacía
Los Enumerable.Aggregate, Enumerable.Average, Enumerable.First, Enumerable.Last, Enumerable.Max, Enumerable.Min, Enumerable.Single y Enumerable.SingleOrDefault realizan operaciones en una secuencia y devuelven un único resultado. Algunas sobrecargas de estos métodos producen una InvalidOperationException excepción cuando la secuencia está vacía, mientras que otras sobrecargas devuelven null
. El Enumerable.SingleOrDefault método también produce una InvalidOperationException excepción cuando la secuencia contiene más de un elemento.
Nota:
La mayoría de los métodos que producen una InvalidOperationException excepción son sobrecargas. Asegúrese de que comprende el comportamiento de la sobrecarga que elija.
En la tabla siguiente se enumeran los mensajes de excepción de los InvalidOperationException objetos de excepción producidos por llamadas a algunos System.Linq.Enumerable métodos.
Método | Mensaje |
---|---|
Aggregate Average Last Max Min |
La secuencia no contiene elementos |
First |
La secuencia no contiene ningún elemento coincidente |
Single SingleOrDefault |
La secuencia contiene más de un elemento coincidente |
La forma de eliminar o manejar la excepción depende de las asunciones de su aplicación y del método particular que usted llame.
Cuando se llama deliberadamente a uno de estos métodos sin comprobar si hay una secuencia vacía, se supone que la secuencia no está vacía y que una secuencia vacía es una aparición inesperada. En este caso, detectar o volver a iniciar la excepción es adecuado.
Si no ha podido comprobar si una secuencia está vacía, puede llamar a una de las sobrecargas de la sobrecarga Enumerable.Any para determinar si una secuencia contiene elementos.
Sugerencia
Llamar al Enumerable.Any<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) método antes de generar una secuencia puede mejorar el rendimiento si los datos que se van a procesar pueden contener un gran número de elementos o si la operación que genera la secuencia es costosa.
Si ha llamado a un método como Enumerable.First, Enumerable.Lasto Enumerable.Single, puede sustituir un método alternativo, como Enumerable.FirstOrDefault, Enumerable.LastOrDefaulto Enumerable.SingleOrDefault, que devuelve un valor predeterminado en lugar de un miembro de la secuencia.
Los ejemplos proporcionan detalles adicionales.
En el ejemplo siguiente se usa el Enumerable.Average método para calcular el promedio de una secuencia cuyos valores son mayores que 4. Dado que ningún valor de la matriz original supera los 4, no se incluye ningún valor en la secuencia y el método produce una InvalidOperationException excepción.
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()
La excepción se puede eliminar llamando al Any método para determinar si la secuencia contiene elementos antes de llamar al método que procesa la secuencia, como se muestra en el ejemplo siguiente.
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: {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.
El Enumerable.First método devuelve el primer elemento de una secuencia o el primer elemento de una secuencia que satisface una condición especificada. Si la secuencia está vacía y, por lo tanto, no tiene un primer elemento, produce una InvalidOperationException excepción.
En el ejemplo siguiente, el Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) método produce una InvalidOperationException excepción porque la matriz dbQueryResults no contiene un elemento mayor que 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 {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()
Puede llamar al Enumerable.FirstOrDefault método en lugar de Enumerable.First para devolver un valor predeterminado o especificado. Si el método no encuentra un primer elemento en la secuencia, devuelve el valor predeterminado para ese tipo de datos. El valor predeterminado es null
para un tipo de referencia, cero para un tipo de datos numérico y DateTime.MinValue para el DateTime tipo.
Nota:
La interpretación del valor devuelto por el Enumerable.FirstOrDefault método suele ser complicada por el hecho de que el valor predeterminado del tipo puede ser un valor válido en la secuencia. En este caso, llama al Enumerable.Any método para determinar si la secuencia tiene miembros válidos antes de llamar al Enumerable.First método .
En el ejemplo siguiente se llama al Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) método para evitar la InvalidOperationException excepción producida en el ejemplo anterior.
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 {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.
Llamada a Enumerable.Single o Enumerable.SingleOrDefault en una secuencia sin un elemento
El Enumerable.Single método devuelve el único elemento de una secuencia o el único elemento de una secuencia que cumple una condición especificada. Si no hay elementos en la secuencia o si hay más de un elemento , el método produce una InvalidOperationException excepción.
Puede usar el Enumerable.SingleOrDefault método para devolver un valor predeterminado en lugar de producir una excepción cuando la secuencia no contiene elementos. Sin embargo, el Enumerable.SingleOrDefault método sigue produciendo una InvalidOperationException excepción cuando la secuencia contiene más de un elemento.
En la tabla siguiente se enumeran los mensajes de excepción de los objetos de excepción InvalidOperationException, generados por llamadas a los métodos Enumerable.Single y Enumerable.SingleOrDefault.
Método | Mensaje |
---|---|
Single |
La secuencia no contiene ningún elemento coincidente |
Single SingleOrDefault |
La secuencia contiene más de un elemento coincidente |
En el ejemplo siguiente, la llamada al Enumerable.Single método produce una InvalidOperationException excepción porque la secuencia no tiene un elemento mayor que 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($"{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 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()
En el ejemplo siguiente se intenta evitar la InvalidOperationException excepción producida cuando una secuencia está vacía mediante una llamada al Enumerable.SingleOrDefault método . Sin embargo, dado que esta secuencia devuelve varios elementos cuyo valor es mayor que 2, también produce una InvalidOperationException excepción.
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($"{singleObject} is the only value greater than 2");
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()
Al llamar al Enumerable.Single método se supone que una secuencia o la secuencia que cumple los criterios especificados contiene solo un elemento. Enumerable.SingleOrDefault supone una secuencia con cero o un resultado, pero no más. Si esta suposición es deliberada por su parte y no se cumplen estas condiciones, volver a iniciar o capturar la excepción InvalidOperationException resultante es adecuado. De lo contrario, o si espera que se produzcan condiciones no válidas con cierta frecuencia, debe considerar la posibilidad de usar algún otro Enumerable método, como FirstOrDefault o Where.
Acceso dinámico a campos de dominio entre aplicaciones
La OpCodes.Ldflda instrucción de lenguaje intermedio común (CIL) produce una InvalidOperationException excepción si el objeto que contiene el campo cuya dirección está intentando recuperar no está dentro del dominio de aplicación en el que se ejecuta el código. Solo se puede acceder a la dirección de un campo desde el dominio de aplicación en el que reside.
Inicio de una excepción InvalidOperationException
Solo debe iniciar una excepción InvalidOperationException cuando el estado del objeto por algún motivo no admite una llamada de método determinada. Es decir, la llamada al método es válida en algunas circunstancias o contextos, pero no es válida en otras.
Si el error de invocación del método se debe a argumentos no válidos, se debe lanzar ArgumentException o una de sus clases derivadas, ArgumentNullException o ArgumentOutOfRangeException, en su lugar.