Let’s say you have a list of HTTP status codes that you read in when the service starts up (perhaps from appsettings.json or from the database). Whenever you send an HTTP request, you want to check if the returned status code is in this list of status code. To make things more efficient, you want to convert the list of status codes to a HashSet<HttpStatusCode>.
To convert a string to an enum, you can use Enum.Parse(). To convert an entire list to a set of enums, you can do the following:
new HashSet<HttpStatusCode>(statusCodes.Select(s => Enum.Parse<HttpStatusCode>(s)));
Code language: C# (cs)
In the rest of this article, I’ll show the code/tests for a generic converter that filters out invalid values.
Generic List<string> to HashSet<EnumT> converter extension method
I want to create a generic converter extension method that has the following behavior:
- It converts a list of strings (enum values, not names) into a set of enums.
- It filters out nulls and whitespace strings.
- It filters out invalid enum values.
You can use this as a starting point and customize the behavior however you want. For example, you may want to throw an exception if any invalid value is detected, instead of just filtering it out.
Tests
To build this converter, I first added the following unit tests one at a time:
[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
The following extension method implements the list-to-set conversion behavior:
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)
I’m using Int32.TryParse() + Enum.IsDefined() instead of just Enum.Parse(), because I want to only accept enum values (not names), and I only want to add valid enum values to the set. The problem with Enum.Parse() is it returns an enum object even if there’s no matching enum value (ex: Enum.Parse(“999”) returns an HttpStatusCode object, even though there’s no status code with the value of 999).
Here’s an example of using this extension method:
//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)
This outputs the following:
RequestTimeout
LengthRequired
PreconditionFailed
RequestEntityTooLarge
UnsupportedMediaType
Code language: plaintext (plaintext)
Comments are closed.