C# – Konvertieren Sie eine Liste von Zeichenfolgen in eine Reihe von Aufzählungen

C# – Konvertieren Sie eine Liste von Zeichenfolgen in eine Reihe von Aufzählungen

Nehmen wir an, Sie haben eine Liste mit HTTP-Statuscodes, die Sie beim Start des Dienstes einlesen (vielleicht aus appsettings.json oder aus der Datenbank). Wann immer Sie eine HTTP-Anforderung senden, möchten Sie prüfen, ob der zurückgegebene Statuscode in dieser Statuscodeliste enthalten ist. Um die Dinge effizienter zu gestalten, möchten Sie die Liste der Statuscodes in ein HashSet.

umwandeln

Um einen String in eine Aufzählung umzuwandeln, können Sie Enum.Parse() verwenden. Um eine ganze Liste in eine Reihe von Aufzählungen umzuwandeln, können Sie Folgendes tun:

new HashSet<HttpStatusCode>(statusCodes.Select(s => Enum.Parse<HttpStatusCode>(s)));
Code language: C# (cs)

Im Rest dieses Artikels zeige ich den Code/die Tests für einen generischen Konverter, der ungültige Werte herausfiltert.

Generic List-zu-HashSet-Konverter-Erweiterungsmethode

Ich möchte eine generische Konverter-Erweiterungsmethode erstellen, die das folgende Verhalten hat:

  • Es wandelt eine Liste von Strings (Aufzählungswerte, keine Namen) in eine Reihe von Aufzählungen um.
  • Es filtert Nullen und Leerzeichen-Strings heraus.
  • Es filtert ungültige Enum-Werte heraus.

Sie können dies als Ausgangspunkt verwenden und das Verhalten nach Ihren Wünschen anpassen. Beispielsweise möchten Sie möglicherweise eine Ausnahme auslösen, wenn ein ungültiger Wert erkannt wird, anstatt ihn einfach herauszufiltern.

Tests

Um diesen Konverter zu erstellen, habe ich zunächst die folgenden Komponententests nacheinander hinzugefügt:

[TestClass()]
public class ListExtensionsTests
{
	[TestMethod()]
	public void TestToSet_HappyPath()
	{
		//arrange
		var list = new List<string>() { "408", "411", "412", "413", "415" };
		var expectedSet = new HashSet<HttpStatusCode>()
		{
			(HttpStatusCode)408,
			(HttpStatusCode)411,
			(HttpStatusCode)412,
			(HttpStatusCode)413,
			(HttpStatusCode)415
		};

		//act
		var set = list.ToSet<HttpStatusCode>();

		//assert
		CollectionAssert.AreEquivalent(expectedSet.ToList(), set.ToList());
	}
	[TestMethod()]
	public void TestToSet_FiltersOutNullAndWhitespaceStrings()
	{
		//arrange
		var list = new List<string>() { "408", null, "", " " };
		var expectedSet = new HashSet<HttpStatusCode>()
		{
			(HttpStatusCode)408
		};

		//act
		var set = list.ToSet<HttpStatusCode>();

		//assert
		CollectionAssert.AreEquivalent(expectedSet.ToList(), set.ToList());
	}
	[TestMethod()]
	public void TestToSet_FiltersOutInvalidEnumValues()
	{
		//arrange
		var list = new List<string>() { "999", "abc" };
		var expectedSet = new HashSet<HttpStatusCode>()
		{
		};

		//act
		var set = list.ToSet<HttpStatusCode>();

		//assert
		CollectionAssert.AreEquivalent(expectedSet.ToList(), set.ToList());
	}
}
Code language: C# (cs)

Code

Die folgende Erweiterungsmethode implementiert das List-to-Set-Konvertierungsverhalten:

using System.Collections.Generic;
using System.Linq;

public static class ListExtensions
{
	public static HashSet<T> ToSet<T>(this List<string> statusCodes) where T : Enum
	{
		return new HashSet<T>(statusCodes.Where(s => !string.IsNullOrWhiteSpace(s)
			&& Int32.TryParse(s, out int intValue)
			&& Enum.IsDefined(typeof(T), intValue))
		.Select(s => (T)Enum.Parse(typeof(T), s)));
	}
}
Code language: C# (cs)

Ich verwende Int32.TryParse() + Enum.IsDefined() statt nur Enum.Parse(), weil ich nur Enum-Werte (keine Namen) akzeptieren und dem Set nur gültige Enum-Werte hinzufügen möchte. Das Problem mit Enum.Parse() ist, dass es ein Enum-Objekt zurückgibt, selbst wenn es keinen passenden Enum-Wert gibt (z. B.:Enum.Parse(„999“) gibt ein HttpStatusCode-Objekt zurück, obwohl es keinen Statuscode mit dem Wert 999 gibt).

Hier ist ein Beispiel für die Verwendung dieser Erweiterungsmethode:

//Get the list of strings from somewhere, like appsettings.json or the database
var list = new List<string>() { "408", "411", "412", "413", "415" };

//Convert to a set for efficient lookups later on
var statusCodeSet = list.ToSet<HttpStatusCode>();


Console.WriteLine(string.Join(Environment.NewLine, statusCodeSet));
Code language: C# (cs)

Dies gibt Folgendes aus:

RequestTimeout
LengthRequired
PreconditionFailed
RequestEntityTooLarge
UnsupportedMediaTypeCode language: plaintext (plaintext)