C# – Schließen Sie Hilfsmethoden zum Auslösen von Ausnahmen aus dem Stack-Trace aus

C# – Schließen Sie Hilfsmethoden zum Auslösen von Ausnahmen aus dem Stack-Trace aus

Wenn Sie eine Methode von der Anzeige im Stack-Trace ausschließen möchten, können Sie das StackTraceHidden-Attribut auf die Methode anwenden:

[System.Diagnostics.StackTraceHidden]
public static void Throw() 
{
	//check conditions and throw
}
Code language: C# (cs)

Hinweis:Dieses Attribut wurde in .NET 6 hinzugefügt.

Sie können StackTraceHidden auf eine Klasse anwenden, um alle ihre Methoden vor dem Stack-Trace zu verbergen:

[System.Diagnostics.StackTraceHidden]
public static class Helpers
{
	//lots of exception thrower helper methods
}
Code language: C# (cs)

Eine sehr nützliche Anwendung des StackTraceHidden-Attributs ist das Ausschließen von Hilfsmethoden zum Auslösen von Ausnahmen aus dem Stack-Trace. Um zu sehen, warum dies nützlich ist, schauen wir uns zunächst manuell geschriebene if-throw-Anweisungen an:

void Process(Employee employee)
{
	if (employee == null)
	{
		throw new ArgumentNullException(nameof(employee));
	}

	if (string.IsNullOrEmpty(employee.FirstName))
	{
		throw new ArgumentNullException(nameof(employee.FirstName));
	}

	//process employee
}
Code language: C# (cs)

Entwickler mögen es normalerweise nicht, diese redundanten if-throw-Anweisungen wiederholt einzugeben, sodass sie am Ende Throw-Hilfsmethoden schreiben oder Drittanbieter-/integrierte Methoden verwenden. Hier ist ein Beispiel für die Verwendung der integrierten Hilfsmethode ArgumentNullException.ThrowIfNull():

void Process(Employee employee)
{
	ArgumentNullException.ThrowIfNull(employee);
	ArgumentNullException.ThrowIfNull(employee.FirstName);

	//process employees
}
Code language: C# (cs)

Hinweis:ArgumentNullException.ThrowIfNull() wurde in .NET 6 hinzugefügt.

Throw-Hilfsmethoden lösen ein Problem (redundante If-Then-Throw-Anweisungen), führen aber ein anderes Problem ein:Stack-Trace-Verschmutzung. Wenn Sie eine Ausnahme auslösen, enthält der Stack-Trace alle Methoden in der Aufrufkette, einschließlich der Throw-Hilfsmethode (und was auch immer sie aufruft) ganz oben:

 System.ArgumentNullException: Value cannot be null. (Parameter 'employee.FirstName')
   at System.ArgumentNullException.Throw(String paramName)
   at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName)
   at Program.Process(Employee employee) in D:\Program.cs:line 19
Code language: plaintext (plaintext)

Die Throw-Hilfsmethode ist irrelevante Information. Es ist nur Rauschen, das die Stack-Trace-Meldung verunreinigt und ihre Interpretation erschwert, insbesondere wenn Sie sie in einer Protokolldatei lesen.

Hier kommt das Attribut StackTraceHidden ins Spiel. Sie können es verwenden, um Ihre eigenen Throw-Hilfsmethoden vor dem Stack-Trace zu verbergen.

using System.Runtime.CompilerServices;
using System.Diagnostics.CodeAnalysis;

[System.Diagnostics.StackTraceHidden]
public static class Helpers
{
	public static void ThrowIfNull([NotNull] object? argument, 
		[CallerArgumentExpression("argument")] string paramName = null)
	{
		if (argument == null)
		{
			throw new ArgumentNullException(paramName);
		}
	}
}
Code language: C# (cs)

Hinweise:1) Dies verwendet das CallerArgumentExpression-Attribut (von .NET 6), um automatisch den übergebenen Parameternamen zu erhalten – genau wie ArgumentNullException.ThrowIfNull() verwendet. 2) Aktualisiert am 26.08.2022. Ein Kommentator wies darauf hin, dass dies eine Nullable-Analyzer-Warnung im aufrufenden Code erzeugt. Machen Sie es zu einem nullable + verwenden Sie [NotNull], um sich darum zu kümmern (d. h. ‚[NotNull] object? argument‘ anstelle von ‚object argument‘)

Hier ist ein Beispiel für den Aufruf dieser Throw-Hilfsmethode:

void Process(Employee employee)
{
	Helpers.ThrowIfNull(employee);
	Helpers.ThrowIfNull(employee.FirstName);

	//process employees
}
Code language: C# (cs)

Hier ist der Stack-Trace. Beachten Sie, dass der Helpers.ThrowIfNull()-Aufruf nicht darin enthalten ist:

System.ArgumentNullException: Value cannot be null. (Parameter 'employee.FirstName')
   at Program.Process(Employee employee) in D:\Program.cs:line 19Code language: plaintext (plaintext)