Freigeben über


Problembehandlung bei Ausnahmen: System.InvalidOperationException

Ein InvalidOperationException wird ausgelöst, wenn eine Methode eines Objekts aufgerufen wird, wenn der Zustand des Objekts den Methodenaufruf nicht unterstützen kann. Die Ausnahme wird auch ausgelöst, wenn eine Methode versucht, die Benutzeroberfläche von einem Thread, der sich nicht im Hauptfenster oder UI-Thread befindet, zu bearbeiten.

Wichtig

Da InvalidOperationExceptions in einer Vielzahl von Bedingungen ausgelöst werden kann, ist es wichtig, die Message gelesen und verstanden haben, die im Ausnahmen-Assistent angezeigt werden.

In diesem Artikel

Eine auf einem UI-Thread-externen ausgeführte Methode aktualisiert die Benutzeroberfläche

Eine Anweisung in einer Foreach (For Each in Visual Basic)-Block ändert die Sammlung, die sie durchläuft

Ein Typ Nullable < T >, der null ist, wird in T umgewandelt.

Eine System.Linq.Enumerable-Methode wird für eine leere Auflistung aufgerufen.

Verwandte Artikel

Die Codebeispiele in diesem Artikel zeigen Ihnen, wie einige häufige InvalidOperationException Ausnahmen in Ihrer Anwendung auftreten können. Wie Sie Probleme behandeln, hängt von der besonderen Situation ab. Wenn die Ausnahme für die Funktionalität Ihrer Anwendung schädlich ist, möchten Sie möglicherweise ein try … catch (Try .. Catch in Visual Basic) Konstrukt verwenden, um die Ausnahme zu erfassen und den Status der Anwendung vor dem Beenden bereinigen. Aber andere InvalidOperationException können erwartet und vermieden werden. Die überarbeitete Methodenbeispiele zeigen Sie einigen dieser Techniken angezeigt.

Eine auf einem UI-Thread-externen ausgeführte Methode aktualisiert die Benutzeroberfläche

Verursacht eine InvalidOperationException mit einem UI-Update von einem nicht-UI-Thread | Vermeiden von InvalidOperationExceptions in nicht-UI-Threads

Die meisten .NET GUI (grafische Benutzeroberfläche) Anwendungs-Frameworks, wie z. B. Windows Forms und Windows Presentation Foundation (WPF) ermöglichen Ihnen den Zugriff auf GUI-Objekte nur aus dem Thread, der die Benutzeroberfläche (denMain- oder UI-Thread). Ein InvalidOperationException wird ausgelöst, wenn Sie versuchen, auf ein Element der Benutzeroberfläche von einem anderen Thread zuzugreifen, der nicht der UI-Thread ist.

Verursacht eine InvalidOperationException mit einem UI-Update von einem nicht-UI-Thread

Hinweis

Die folgenden Beispiele verwenden die Aufgabenbasiertes asynchrones Muster (TAP, Task-based Asynchronous Pattern), um nicht-UI-Threads zu erstellen.Die Beispiele gelten jedoch auch für alle relevanten Muster für die asynchrone Programmierung.

In diesen Beispielen ruft der ThreadsExampleBtn_Click Ereignishandler die DoSomeWork-Methode zweimal auf. Der erste Aufruf der Methode (DoSomeWork(20); wird synchron ausgeführt und erfolgreich abgeschlossen. Aber der zweite Aufruf (Task.Run( () => { DoSomeWork(1000);});) erfolgt über einen Thread im Thread-Pool der Anwendung. Da dieser Aufruf versucht, die Benutzeroberfläche von einem nicht-UI-Thread zu aktualisieren, wird durch die Anweisung einInvalidOperationException ausgelöst

WPF und Store-Anwendungen

Hinweis

In Store Phone-Anwendungen wird ein Exception anstatt der spezifischeren InvalidOperationException ausgelöst.

Ausnahmemeldungen:

WPF-Anwendungen

Zusätzliche Informationen: Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da ein anderer Thread es besitzt.

Store-Apps

Weitere Informationen: Die Anwendung rief eine Schnittstelle auf, die für einen anderen Thread der Anwendung aufgerufen wurde. (Ausnahme von HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

private async void ThreadsExampleBtn_Click(object sender, RoutedEventArgs e)
{
    TextBox1.Text = String.Empty;

    TextBox1.Text = "Simulating work on UI thread.\n";
    DoSomeWork(20);

    TextBox1.Text += "Simulating work on non-UI thread.\n";
    await Task.Run(() => DoSomeWork(1000));

    TextBox1.Text += "ThreadsExampleBtn_Click completes. ";
}

private void DoSomeWork(int msOfWork)
{
    // simulate work
    var endTime = DateTime.Now.AddMilliseconds(msOfWork);
    while (DateTime.Now < endTime)
    {
        // spin
    };

    // report completion
    var msg = String.Format("Some work completed in {0} ms on UI thread. \n", msOfWork);
    TextBox1.Text += msg;
}

Windows Forms-Anwendungen

Ausnahmemeldung:

  • Weitere Informationen: threadübergreifender Vorgang ungültig: Steuerelement "TextBox1" von einem anderen Thread als dem erstellten Thread aufgerufen.
private async void ThreadsExampleBtn_Click(object sender, EventArgs e)
{
    TextBox1.Text = String.Empty;

    var tbLinesList = new List<string>() {"Simulating work on UI thread."};
    TextBox1.Lines = tbLinesList.ToArray();
    DoSomeWork(20, tbLinesList);

    tbLinesList.Add("Simulating work on non-UI thread.");
    TextBox1.Lines = tbLinesList.ToArray();
    await Task.Run(() => DoSomeWork(1000, tbLinesList));

    tbLinesList.Add("ThreadsExampleBtn_Click completes.");
    TextBox1.Lines = tbLinesList.ToArray();
}
private void DoSomeWork(int msOfWork, List<string> tbLinesList)
{
    // simulate work
    var endTime = DateTime.Now.AddMilliseconds(msOfWork);
    while (DateTime.Now < endTime) { };
    {
        // spin
    };

    // report completion
    var msg = String.Format("Some work completed in {0} ms on UI thread. \n", msOfWork);
    tbLinesList.Add(msg);
    TextBox1.Lines = tbLinesList.ToArray();
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Vermeiden von InvalidOperationExceptions in nicht-UI-Threads

Windows-Benutzeroberflächen-Frameworks implementieren ein Dispatcher-Muster, das eine Methode umfasst, mit der überprüft werden kann, ob ein Aufruf an ein Mitglied eines Benutzeroberflächenelements auf dem UI-Thread ausgeführt wird, und andere Methoden, um den Anruf an den UI-Thread zu planen.

WPF-Anwendungen

In WPF-Anwendungen verwenden Sie eine der Dispatcher.Invoke-Methoden, um einen Delegaten auf dem UI-Thread auszuführen. Verwenden Sie bei Bedarf die Dispatcher.CheckAccess-Methode, um festzulegen, ob eine Methode in einem nicht-UI-Thread ausgeführt wird oder nicht.

private void DoSomeWork(int msOfWork)
{
    var endTime = DateTime.Now.AddMilliseconds(msOfWork);
    while (DateTime.Now < endTime)
    {
        // spin
    };

    // report completion
    var msgFormat = "Some work completed in {0} ms on {1}UI thread.\n";
    var msg = String.Empty;
    if (TextBox1.Dispatcher.CheckAccess())
    {
        msg = String.Format(msgFormat, msOfWork, String.Empty);
        TextBox1.Text += msg;
    }
    else
    {
        msg = String.Format(msgFormat, msOfWork, "non-");
        Action act = ()=> {TextBox1.Text += msg;};
        TextBox1.Dispatcher.Invoke(act);
    }
}

Windows Forms-Anwendungen

In Windows Forms-Anwendungen verwenden die Control.Invoke-Methode, um einen Delegaten auszuführen, der den UI-Thread aktualisiert. Verwenden Sie bei Bedarf die Control.InvokeRequired-Methode, um festzulegen, ob eine Methode in einem nicht-UI-Thread ausgeführt wird oder nicht.

private void DoSomeWork(int msOfWork, List<string> tbLinesList)
{
    // simulate work
    var endTime = DateTime.Now.AddMilliseconds(msOfWork);
    while (DateTime.Now < endTime)
    {
        // spin
    };

    // report completion
    var msgFormat = "Some work completed in {0} ms on {1}UI thread.\n";
    var msg = String.Empty;
    if (TextBox1.InvokeRequired)
    {
        msg = String.Format(msgFormat, msOfWork, "non-");
        tbLinesList.Add(msg);
        Action act = () => TextBox1.Lines = tbLinesList.ToArray();
        TextBox1.Invoke( act );
    }
    else
    {
        msg = String.Format(msgFormat, msOfWork, String.Empty);
        tbLinesList.Add(msg);
        TextBox1.Lines = tbLinesList.ToArray();
    }
}

Store-Apps

In Windows Forms-Anwendungen verwenden Sie die CoreDispatcher.RunAsync-Methode, um einen Delegaten auszuführen, der den UI-Thread aktualisiert. Verwenden Sie bei Bedarf die HasThreadAccess-Methode, um festzulegen, ob eine Methode in einem nicht-UI-Thread ausgeführt wird oder nicht.

private void DoSomeWork(int msOfWork)
{
    // simulate work
    var endTime = DateTime.Now.AddMilliseconds(msOfWork);
    while (DateTime.Now < endTime)
    {
        // spin
    };

    // report completion
    var msgFormat = "Some work completed in {0} ms on {1}UI thread.\n";
    var msg = String.Empty;

    if (TextBox1.Dispatcher.HasThreadAccess)
    {
        msg = String.Format(msgFormat, msOfWork, String.Empty);
        TextBox1.Text += msg;
    }
    else
    {
        msg = String.Format(msgFormat, msOfWork, "non-");
        TextBox1.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,  
            ()=> {TextBox1.Text += msg;});
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Eine Anweisung in einer Foreach (For Each in Visual Basic)-Block ändert die Sammlung, die sie durchläuft

Verursacht eine InvalidOperationException mit foreach | Vermeidet InvalidOperationExceptions in Schleifen

Eine foreach-Anweisung (For Each in Visual Basic) wiederholt eine Gruppe von eingebetteten Anweisungen für jedes Element in einem Array oder einer Auflistung, die die IEnumerable oder IEnumerable-Schnittstelle implementiert. Die foreach-Anweisung wird zum Durchlaufen der Auflistung zum Lesen und Ändern der Elemente, aber nicht zum Hinzufügen oder Entfernen von Elementen aus der Auflistung verwendet. Ein InvalidOperationException wird ausgelöst, wenn Sie Elemente aus der Auflistung in einer Foreach-Anweisung hinzufügen oder daraus entfernen.

Verursacht eine InvalidOperationException mit foreach

In diesem Beispiel wird eine InvalidOperationException ausgelöst, wenn die numList.Add(5);-Anweisung versucht, die Liste im Foreach-Block zu ändern.

Ausnahmemeldung:

  • Zusätzliche Informationen: Die Auflistung wurde geändert; der Enumerationsvorgang kann nicht ausgeführt werden.
private void AddElementsToAList()
{
    var numList = new List<int>() { 1, 2, 3, 4 };

    foreach (var num in numList)
    {
        if (num == 2)
        {
            numList.Add(5);
        }
    }

    // Display list elements
    foreach (var num in numList)
    {
        Console.Write("{0} ", num);
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Vermeidet InvalidOperationExceptions in Schleifen

Wichtig

Das Hinzufügen oder Entfernen von Elementen zu einer Liste während Sie die Sammlung durchlaufen können unbeabsichtigte und schwer vorhersagbare Nebenwirkungen haben.Wenn möglich, sollten Sie den Vorgang außerhalb der Iteration verschieben.

private void AddElementsToAList ()
{
    var numList = new List<int>() { 1, 2, 3, 4 };

    var numberOf2s = 0;

    foreach (var num in numList)
    {
        if (num == 2)
        {
            numberOf2s++;
        }
    }

    for (var i = 0; i < numberOf2s; i++ ) 
    { 
        numList.Add(5); 
    }

    // Display list elements
    foreach (var num in numList)
    {
        Console.Write("{0} ", num);
    }
}

Falls Ihre Situation erfordet, dass Sie Elemente zu einer Liste hinzufügen oder daraus entfernen, während Sie eine Liste durchlaufen, verwenden Sie eine Schleife für (für in Visual Basic):

private void AddElementsToAList ()
{
    var numList = new List<int>() { 1, 2, 3, 4 };

    for (var i = 0; i < numList.Count; i++) 
    {
        if (numList[i] == 2)
        {
            numList.Add(5);
        }
    }

    // Display list elements
    foreach (var num in numList)
    {
        Console.Write("{0} ", num);
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Ein Typ Nullable < T >, der null ist, wird in T umgewandelt.

Verursachen einer InvalidOperationException mit einer ungültigen Umwandlung | Vermeiden von InvalidOperationException aus eine ungültigen Umwandlung

Wenn Sie eine StrukturNullable auslösen, die in dem zugrunde liegenden Typ null (Nothing in Visual Basic) ist, wird eine InvalidOperationException-Ausnahme ausgelöst.

Verursachen einer InvalidOperationException mit einer ungültigen Umwandlung

Bei dieser Methode wird eine InvalidOperationException ausgelöst, wenn die Select-Methode ein null-Element des DbQueryResults in int umgewandelt

Ausnahmemeldung:

  • Weitere Informationen: Auf null festlegbares Objekt muss einen Wert haben.
private void MapQueryResults()
{
    var dbQueryResults = new int?[] { 1, 2, null, 4 };

    var ormMap = dbQueryResults.Select(nullableInt => (int)nullableInt);

    //display map list
    foreach (var num in ormMap)
    {
        Console.Write("{0} ", num);
    }
    Console.WriteLine();
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Vermeiden von InvalidOperationException aus eine ungültigen Umwandlung

Um InvalidOperationException zu vermeiden:

  • Verwenden Sie die Nullable.HasValue-Eigenschaft, um nur die Elemente auszuwählen, die nicht null sind.

  • Verwenden Sie eine der überladenen Nullable.GetValueOrDefault Methoden, um einen Standardwert für ein null-Element anzugeben.

Nullable < T >.HasValue Beispiel

private void MapQueryResults()
{
    var dbQueryResults = new int?[] { 1, 2, null, 4 };

    var ormMap = dbQueryResults
        .Where(nulllableInt => nulllableInt.HasValue)
        .Select(num => (int)num);

    //display map list
    foreach (var num in ormMap)
    {
        Console.Write("{0} ", num);
    }
    Console.WriteLine();

    // handle nulls
    Console.WriteLine("{0} nulls encountered in dbQueryResults",
        dbQueryResults.Where(nullableInt => !nullableInt.HasValue).Count());
}

Nullable < T >.GetValueOrDefault Beispiel

In diesem Beispiel verwenden wir GetValueOrDefault(UTP) zur Angabe eines Standardwertes, der außerhalb der von dbQueryResults zurückgegebenen erwarteten Werten liegt.

private void MapQueryResults()
{
    var dbQueryResults = new int?[] { 1, 2, null, 4 };
    var nullFlag = int.MinValue;

    var ormMap = dbQueryResults.Select(nullableInt => nullableInt.GetValueOrDefault(nullFlag));

    // handle nulls
    Console.WriteLine("'{0}' indicates a null database value.", nullFlag);

    foreach (var num in ormMap)
    {
        Console.Write("{0} ", num);
    }
    Console.WriteLine();
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Eine System.Linq.Enumerable-Methode wird für eine leere Auflistung aufgerufen.

Die Enumerable MethodenAggregate, Average, Last, Max, Min, First, Single und SingleOrDefault führen Operationen für eine Sequenz durch und geben ein Einzelergebnis zurück.

Einige Überladungen dieser Methoden lösen eine InvalidOperationException Ausnahme aus, wenn die Sequenz leer ist (andere Überladungen gebennull (Nothing in Visual Basic) zurück. SingleOrDefaultlöst außerdem InvalidOperationException aus, wenn die Sequenz mehr als ein Element enthält.

Tipp

Die meisten der Enumerable in diesem Abschnitt diskutierten Methoden sind überladen.Achten Sie darauf, dass Sie das Verhalten der Überladung verstehen, die Sie auswählen.

Ausnahmemeldungen:

Summe, Durchschnitt, Letzte, Max und Min Methoden | First und FirstOrDefault-Methoden | Single- und SingleOrDefault-Methoden

Summe, Durchschnitt, Letzte, Max und Min Methoden

  • Weitere Informationen: Sequenz enthält keine Elemente

Verursacht eine InvalidOperationException mit Durchschnitt

In diesem Beispiel löst die folgende Methode eine InvalidOperationException aus, wenn sie die Average-Methode aufruft, da der Ausdruck Linq eine Sequenz zurückgibt, die keine Elemente enthält, die größer sind als 4.

private void FindAverageOfNumbersGreaterThan4()
{
    var dbQueryResults = new[] { 1, 2, 3, 4 };

    var avg = dbQueryResults.Where(num => num > 4).Average();

    Console.WriteLine("The average value numbers greater than 4 in the returned records is {0}", avg);
}

Wenn Sie eine dieser Methoden verwenden, ohne eine Überprüfung auf eine leere Sequenz durchzuführen, gehen Sie implizit davon aus, dass die Sequenz nicht leer ist und eine leere Sequenz ein unerwartetes Ereignis ist. Das Abfangen oder Auslösen der Ausnahme ist geeignet, wenn Sie davon ausgehen, dass die Sequenz nicht leer ist.

Vermeiden Sie eine InvalidOperationException, die von einer leeren Sequenz zurückgeführt wird.

Verwenden Sie eine der Enumerable.Any Methoden, um zu überprüfen, ob die Sequenz leer ist.

Tipp

Mit Any kann die Prüfleistung verbessert werden, wenn die Sequenz, die durchschnittliche Sequenz möglicherweise eine große Anzahl von Elementen enthält oder wenn die Operation, die die Sequenz generiert, teuer ist.

private void FindAverageOfNumbersGreaterThan4()
{
    var dbQueryResults = new[] { 1, 2, 3, 4 };

    var moreThan4 = dbQueryResults.Where(num => num > 4);

    if(moreThan4.Any())
    {
        var msgFormat = "The average value numbers greater than 4 in the returned records is {0}";
        Console.WriteLine(msgFormat, moreThan4.Average());
    }
    else
    {
        // handle empty collection 
        Console.WriteLine("There are no values greater than 4 in the ecords.");
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

First und FirstOrDefault-Methoden

First gibt das erste Element in einer Sequenz zurück oder löst eine InvalidOperationException aus, wenn die Sequenz leer ist. Sie erreichen die FirstOrDefault-Methode anstelle von First zum Zurückgeben eines angegebenen Werts oder Standardwerts, statt die Ausnahme auszulösen.

Hinweis

Im .NET Framework verfügen Typen über ein Konzept von Standardwerten.Für jeden Referenztyp ist der Standardwert beispielsweise null, und für einen Integertyp ist er 0 (null).Siehe Tabelle für Standardwerte (C#-Referenz).

Auslösen einer InvalidOperationException mit First

Die First ist eine Methode der Leistungsoptimierung, die das erste Element in einer Sequenz zurückgeben wird, die eine angegebene Bedingung erfüllt. Wenn ein Element, das die Bedingung nicht erfüllt, nicht gefunden wird, lösen die Methoden eine InvalidOperationException Ausnahme aus.

In diesem Beispiel löst die First-Methode eine Ausnahme aus, da dbQueryResults kein Element enthält, das größer als 4 ist.

Ausnahmemeldung:

  • Zusätzliche Informationen: Die Sequenz enthält kein übereinstimmendes Element
private void FindANumbersGreaterThan4()
{
    var dbQueryResults = new[] { 1, 2, 3, 4 };

    var firstNum = dbQueryResults.First(n=> n > 4);

    var msgFormat = "{0} is an element of dbQueryResults that is greater than 4";
    Console.WriteLine(msgFormat, firstNum);

}

Vermeiden einer Ausnahme mit "FirstOrDefault"

Verwenden Sie eine der FirstOrDefault-Methoden anstelle von First, um zu prüfen, ob die firstNum Sequenz mindestens ein Element enthält. Wenn bei der Abfrage kein Element gefunden wird, das die Bedingung erfüllt, gibt sie einen angegebenen oder Standardwert zurück. Sie können den zurückgegebenen Wert überprüfen, um festzustellen, ob alle Elemente gefunden werden.

Hinweis

Mit kann FirstOrDefault schwieriger zu implementieren sein, wenn der Standardwert des Typs ein gültiges Element in der Sequenz ist.

private void FindANumbersGreaterThan4()
{
    var dbQueryResults = new[] { 1, 2, 3, 4 };

    // default(object) == null
    var firstNum = dbQueryResults.FirstOrDefault(n => n > 4);

    if (firstNum != 0)
    {
        var msgFormat = "{0} is an element of dbQueryResults that is greater than 4";
        Console.WriteLine(msgFormat, firstNum);
    }
    else
    {
        // handle default case
        Console.WriteLine("No element of dbQueryResults is greater than 4.");
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Single- und SingleOrDefault-Methoden

Die Enumerable.Single-Methode gibt das einzige Element einer Sequenz oder das einzige Element einer Sequenz, das einen angegebenen Test besteht, zurück.

Wenn keine Elemente in der Sequenz vorhanden sind, oder wenn mehr als ein Element in der Sequenz vorhanden ist, löst die Methode eine InvalidOperationException Ausnahme aus.

Sie können SingleOrDefault zum Zurückgeben eines angegebenen Werts oder Standardwerts verwenden, anstatt die Ausnahme auszulösen, wenn die Sequenz keine Elemente enthält. Allerdings löst SingleOrDefault immer noch ein InvalidOperationException aus, wenn die Sequenz mehr als ein Element enthält, das das Auswahlprädikat erfüllt.

Hinweis

Im .NET Framework verfügen Typen über ein Konzept von Standardwerten.Für jeden Referenztyp ist der Standardwert beispielsweise null, und für einen Integertyp ist er 0 (null).Siehe Tabelle für Standardwerte (C#-Referenz).

Auslösen von InvalidOperationExceptions mit

In diesem Beispiel löst singleObject eine InvalidOperationException aus, da dbQueryResults kein Element enthält, das größer als 4 ist.

Ausnahmemeldung:

  • Zusätzliche Informationen: Die Sequenz enthält kein übereinstimmendes Element
private void FindTheOnlyNumberGreaterThan4()
{
    var dbQueryResults = new[] { (object)1, (object)2, (object)3, (object)4 };

    var singleObject = dbQueryResults.Single(obj => (int)obj > 4);

    // display results
    var msgFormat = "{0} is the only element of dbQueryResults that is greater than 4";
    Console.WriteLine(msgFormat, singleObject);
}

Auslösen von InvalidOperationExceptions mit Single oder SingleOrDefault

In diesem Beispiel löst singleObject eine InvalidOperationException aus, da dbQueryResults mehr als ein Element enthält, das größer ist als 2.

Ausnahmemeldung:

  • Zusätzliche Informationen: die Sequenz enthält mehrere übereinstimmende Elemente
private void FindTheOnlyNumberGreaterThan2()
{
    var dbQueryResults = new[] { (object)1, (object)2, (object)3, (object)4 };

    var singleObject = dbQueryResults.SingleOrDefault(obj => (int)obj > 2);

    if (singleObject != null)
    {
        var msgFormat = "{0} is the only element of dbQueryResults that is greater than 2";
        Console.WriteLine(msgFormat, singleObject);
    }
    else
    {
        // handle empty collection
        Console.WriteLine("No element of dbQueryResults is greater than 2.");
    }
}

Vermeiden von InvalidOperationExceptions mit Single

Single und SingleOrDefault dienen auch als Dokumentation für Ihre Absichten. Single stark setzt voraus, dass Sie erwarten, dass nur ein Ergebnis aus dem Zustand zurückgegeben wird. SingleOrDefault deklariert, dass Sie ein oder null aber nicht mehr Ergebnisse erwarten. Wenn diese Bedingungen nicht zutreffen, ist das Auslösen und Abfangen der InvalidOperationException geeignet. Wenn Sie jedoch erwarten, dass ungültige Bedingungen häufig auftreten, sollten Sie mit anderen Enumerable-Methoden, z. B. First oder Where die Ergebnisse generieren.

Während der Entwicklung können Sie mit einer der Assert-Methoden Ihre Annahmen überprüfen. In diesem Beispiel bewirkt der hervorgehobene Code, dass der Debugger bricht, und zeigt das Dialogfeld Assert während der Entwicklung an. Die Assertion ist im Versions-Code entfernt, und jede Single wird ausgelöst, wenn die Ergebnisse ungültig sind.

Hinweis

Mit Take``1 und der Konfiguration seines count-Parameters auf 2 wird die zurückgegebene Sequenz auf höchstens zwei Elemente beschränkt.Diese Reihenfolge gilt auch für alle Fälle, die Sie benötigen, um (0, 1 und mehr als 1 Elemente) zu überprüfen, und kann die Prüfleistung verbessern, wenn die Sequenz eine große Anzahl von Elementen enthält oder wenn die Operation, die die Sequenz generiert, teuer ist.

private void FindTheOnlyNumberGreaterThan4()
{
    var dbQueryResults = new[] { (object)1, (object)2, (object)3, (object)4 };
    var moreThan4 = dbQueryResults.Where(obj => (int)obj > 4).Take(2);

    System.Diagnostics.Debug.Assert(moreThan4.Count() == 1, 
        String.Format("moreThan4.Count() == 1; Actual count: {0}", moreThan4.Count()));

    // do not handle exceptions in release code
    Console.WriteLine("{0} is the only element of dbQueryResults that is greater than 4", 
        moreThan4.Single());
}

Wenn Sie die Ausnahme verhindern, aber immernoch die ungültigen Zustände im Versions-Code behandeln möchten, können Sie das oben beschriebene Verfahren ändern. In diesem Beispiel reagiert die Methode auf die Anzahl von zurückgegebenen Elementen moreThan2 in der Switch-Anweisung.

private void FindTheOnlyNumberGreaterThan2()
{
    var dbQueryResults = new[] { (object)1, (object)2, (object)3, (object)4 };

    var moreThan2 = dbQueryResults.TakeWhile(obj => (int)obj > 2).Take(2);

    switch(moreThan2.Count())
    { 
        case 1:
            // success
            var msgFormat = "{0} is the only element of dbQueryResults that is greater than 2";
            Console.WriteLine(msgFormat, moreThan2.Single());
            break;
        case 0:
            // handle empty collection
            Console.WriteLine("No element of the dbQueryResults are greater than 4.");
            break;
        default: // count > 1
            // handle more than one element
            Console.WriteLine("More than one element of dbQueryResults is greater than 4");
            break;
    }
}

Zurück nach obenIn diesem ArtikelIn diesem AbschnittIn diesem Abschnitt

Verwandte Artikel

Entwurfsrichtlinien für Ausnahmen (.NET Framework-Entwurfsrichtlinien)

Behandeln und Auslösen von Ausnahmen (.NET Framework-Anwendungsgrundlagen)

Vorgehensweise:Empfangen von Ausnahmebenachrichtigungen (.NET Framework-Entwicklungsleitfaden)

Vorgehewnsweise:Behandeln von Ausnahmen in einer PLINQ-Abfrage (.NET Framework-Entwicklungsleitfaden)

Ausnahmen in verwalteten Threads (.NET Framework-Entwicklungsleitfaden)

Ausnahmen und Ausnahmebehandlung (C#-Programmierhandbuch)

Ausnahmebehandlungsanweisungen (C#-Referenz)

Try...Catch...Finally-Anweisung (Visual Basic)

Ausnahmebehandlung (F#)

Ausnahmen in C++/CLI

Ausnahmebehandlung (Task Parallel Library)

Ausnahmebehandlung (Debugging)

Exemplare Vorgehensweise: Behandeln einer Parallelitätsausnahme (Datenzugriff in Visual Studio)

Vorgehensweise: Behandeln von Fehlern und Ausnahmen in Zusammenhang mit der Datenbindung (Windows Forms)

Behandeln von Ausnahmen in Netzwerk-Apps (XAML) (Windows)

Zurück nach obenIn diesem Artikel