C#:excluir los métodos auxiliares de lanzamiento de excepciones del seguimiento de la pila

C#:excluir los métodos auxiliares de lanzamiento de excepciones del seguimiento de la pila

Cuando desee excluir un método para que no aparezca en el seguimiento de la pila, puede aplicar el atributo StackTraceHidden al método:

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

Nota:este atributo se agregó en .NET 6.

Puede aplicar StackTraceHidden a una clase para ocultar todos sus métodos del seguimiento de la pila:

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

Una aplicación muy útil del atributo StackTraceHidden es excluir los métodos auxiliares de generación de excepciones del seguimiento de la pila. Para ver por qué esto es útil, comencemos mirando declaraciones if-then-throw escritas manualmente:

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)

Por lo general, a los desarrolladores no les gusta escribir repetidamente estas declaraciones if-then-throw redundantes, por lo que terminan escribiendo métodos auxiliares de lanzamiento o utilizando métodos incorporados o de terceros. Este es un ejemplo del uso del método auxiliar ArgumentNullException.ThrowIfNull() incorporado:

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

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

Nota:ArgumentNullException.ThrowIfNull() se agregó en .NET 6.

Los métodos auxiliares de lanzamiento resuelven un problema (sentencias if-then-throw redundantes), pero introducen otro problema:la contaminación del seguimiento de la pila. Cuando lanza una excepción, el seguimiento de la pila incluye todos los métodos en la cadena de llamadas, incluido el método auxiliar de lanzamiento (y lo que sea que llame) justo en la parte superior:

 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)

El método throw helper es información irrelevante. Es solo ruido lo que contamina el mensaje de seguimiento de la pila, lo que lo hace más difícil de interpretar, especialmente cuando lo lee en un archivo de registro.

Aquí es donde entra en juego el atributo StackTraceHidden. Puede usarlo para ocultar sus propios métodos auxiliares de lanzamiento del seguimiento de la pila.

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)

Notas:1) Esto usa el atributo CallerArgumentExpression (de .NET 6) para obtener automáticamente el nombre del parámetro pasado, al igual que lo que usa ArgumentNullException.ThrowIfNull(). 2) Actualizado el 2022-08-26. Un comentarista señaló que esto produce una advertencia de analizador anulable en el código de llamada. Conviértalo en anulable + use [NotNull] para encargarse de eso (es decir, '[NotNull] object? argument' en lugar de 'object argument')

Este es un ejemplo de cómo llamar a este método auxiliar de lanzamiento:

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

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

Aquí está el seguimiento de la pila. Observe que no tiene la llamada Helpers.ThrowIfNull():

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