Skip to content

Commit 9aa23f3

Browse files
authored
Merge pull request #2743 from jnyrup/type_dictionary
Apply the Type-Dictionary Trick
2 parents c4df9a1 + 2723ae2 commit 9aa23f3

File tree

4 files changed

+71
-60
lines changed

4 files changed

+71
-60
lines changed

lib/PuppeteerSharp.Tests/BrowserContextTests/BrowserContextOverridePermissionsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public async Task AllEnumsdAreValid()
111111
await Page.GoToAsync(TestConstants.EmptyPage);
112112
await Context.OverridePermissionsAsync(
113113
TestConstants.EmptyPage,
114-
Enum.GetValues(typeof(OverridePermission)).Cast<OverridePermission>().ToArray());
114+
Enum.GetValues<OverridePermission>());
115115
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("granted"));
116116
await Context.ClearPermissionOverridesAsync();
117117
Assert.That(await GetPermissionAsync(Page, "geolocation"), Is.EqualTo("prompt"));

lib/PuppeteerSharp/BrowserData/Cache.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using PuppeteerSharp.Helpers;
56

67
namespace PuppeteerSharp.BrowserData
78
{
@@ -27,12 +28,12 @@ public IEnumerable<InstalledBrowser> GetInstalledBrowsers()
2728
return Array.Empty<InstalledBrowser>();
2829
}
2930

30-
var browserNames = Enum.GetNames(typeof(SupportedBrowser)).Select(browser => browser.ToUpperInvariant());
31+
var browserNames = EnumHelper.GetNames<SupportedBrowser>().Select(browser => browser.ToUpperInvariant());
3132
var browsers = rootInfo.GetDirectories().Where(browser => browserNames.Contains(browser.Name.ToUpperInvariant()));
3233

3334
return browsers.SelectMany(browser =>
3435
{
35-
var browserEnum = (SupportedBrowser)Enum.Parse(typeof(SupportedBrowser), browser.Name, ignoreCase: true);
36+
var browserEnum = EnumHelper.Parse<SupportedBrowser>(browser.Name, ignoreCase: true);
3637
var dirInfo = new DirectoryInfo(GetBrowserRoot(browserEnum));
3738
var dirs = dirInfo.GetDirectories();
3839

@@ -45,7 +46,7 @@ public IEnumerable<InstalledBrowser> GetInstalledBrowsers()
4546
return null;
4647
}
4748

48-
var platformEnum = (Platform)Enum.Parse(typeof(Platform), result.Value.Platform, ignoreCase: true);
49+
var platformEnum = EnumHelper.Parse<Platform>(result.Value.Platform, ignoreCase: true);
4950
return new InstalledBrowser(this, browserEnum, result.Value.BuildId, platformEnum);
5051
})
5152
.Where(item => item != null);

lib/PuppeteerSharp/BrowserData/Firefox.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ internal static void CreateProfile(string tempUserDataDirectory, Dictionary<stri
131131
private static (FirefoxChannel Channel, string BuildId) ParseBuildId(string buildId)
132132
{
133133
// Iterate through all the FirefoxChannel enum values as string
134-
foreach (var value in Enum.GetValues(typeof(FirefoxChannel)).Cast<FirefoxChannel>().Select(v => v.ToValueString()))
134+
foreach (var value in EnumHelper.GetValues<FirefoxChannel>().Select(v => v.ToValueString()))
135135
{
136136
if (buildId.StartsWith(value, StringComparison.OrdinalIgnoreCase))
137137
{

lib/PuppeteerSharp/Helpers/EnumHelper.cs

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
// * SOFTWARE.
2222

2323
using System;
24-
using System.Collections.Concurrent;
2524
using System.Collections.Generic;
2625
using System.Reflection;
2726
using System.Runtime.Serialization;
@@ -31,86 +30,97 @@ namespace PuppeteerSharp.Helpers;
3130

3231
internal static class EnumHelper
3332
{
34-
private static readonly ConcurrentDictionary<Type, IReadOnlyDictionary<string, Enum>> _stringToEnumCache = new();
33+
public static string[] GetNames<TEnum>()
34+
where TEnum : struct, Enum =>
35+
#if NET8_0_OR_GREATER
36+
Enum.GetNames<TEnum>();
37+
#else
38+
Enum.GetNames(typeof(TEnum));
39+
#endif
3540

36-
private static readonly ConcurrentDictionary<Type, IReadOnlyDictionary<Enum, string>> _enumToStringCache = new();
41+
public static TEnum[] GetValues<TEnum>()
42+
where TEnum : struct, Enum =>
43+
#if NET8_0_OR_GREATER
44+
Enum.GetValues<TEnum>();
45+
#else
46+
(TEnum[])Enum.GetValues(typeof(TEnum));
47+
#endif
3748

38-
public static TEnum ToEnum<TEnum>(this string value)
39-
where TEnum : Enum
40-
{
41-
var enumValues = _stringToEnumCache.GetOrAdd(typeof(TEnum), type =>
42-
{
43-
var names = Enum.GetNames(type);
44-
var values = (TEnum[])Enum.GetValues(type);
45-
var dictionary = new Dictionary<string, Enum>(StringComparer.OrdinalIgnoreCase);
46-
for (var i = 0; i < names.Length; i++)
47-
{
48-
dictionary.Add(names[i], values[i]);
49-
var memberValue = type.GetField(names[i]).GetCustomAttribute<EnumMemberAttribute>()?.Value;
50-
if (memberValue != null)
51-
{
52-
dictionary[memberValue] = values[i];
53-
}
54-
}
49+
public static TEnum Parse<TEnum>(string value, bool ignoreCase)
50+
where TEnum : struct, Enum =>
51+
#if NET8_0_OR_GREATER
52+
Enum.Parse<TEnum>(value, ignoreCase);
53+
#else
54+
(TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
55+
#endif
5556

56-
return dictionary;
57-
});
58-
return (TEnum)enumValues[value];
59-
}
57+
public static TEnum ToEnum<TEnum>(this string value)
58+
where TEnum : struct, Enum
59+
=> StringToEnum<TEnum>.Cache[value];
6060

6161
public static string ToValueString<TEnum>(this TEnum value)
62-
where TEnum : Enum
62+
where TEnum : struct, Enum
63+
=> EnumToString<TEnum>.Cache[value];
64+
65+
public static TEnum FromValueString<TEnum>(string value)
66+
where TEnum : struct, Enum
6367
{
64-
var enumValues = _enumToStringCache.GetOrAdd(typeof(TEnum), type =>
68+
if (StringToEnum<TEnum>.Cache.TryGetValue(value, out var enumValue))
6569
{
66-
var names = Enum.GetNames(type);
67-
var dictionary = new Dictionary<Enum, string>();
68-
foreach (var t in names)
69-
{
70-
var field = type.GetField(t);
71-
var valueName = field.GetCustomAttribute<EnumMemberAttribute>()?.Value ?? t;
72-
var fieldValue = (TEnum)field.GetValue(null);
73-
dictionary[fieldValue] = valueName;
74-
}
70+
return enumValue;
71+
}
7572

76-
return dictionary;
77-
});
73+
var defaultEnumAttribute = typeof(TEnum).GetCustomAttribute<DefaultEnumValueAttribute>();
74+
if (defaultEnumAttribute != null)
75+
{
76+
return (TEnum)(object)defaultEnumAttribute.Value;
77+
}
7878

79-
return enumValues[value];
79+
throw new ArgumentException($"Unknown value '{value}' for enum {typeof(TEnum).Name}");
8080
}
8181

82-
public static TEnum FromValueString<TEnum>(string value)
82+
private static class StringToEnum<TEnum>
8383
where TEnum : struct, Enum
8484
{
85-
var enumValues = _stringToEnumCache.GetOrAdd(typeof(TEnum), type =>
85+
public static readonly IReadOnlyDictionary<string, TEnum> Cache = Compute();
86+
87+
private static Dictionary<string, TEnum> Compute()
8688
{
87-
var names = Enum.GetNames(type);
88-
var dictionary = new Dictionary<string, Enum>(StringComparer.OrdinalIgnoreCase);
89-
foreach (var valueName in names)
89+
var names = GetNames<TEnum>();
90+
var dictionary = new Dictionary<string, TEnum>(StringComparer.OrdinalIgnoreCase);
91+
foreach (var name in names)
9092
{
91-
var field = type.GetField(valueName);
93+
var field = typeof(TEnum).GetField(name);
9294
var fieldValue = (TEnum)field.GetValue(null);
93-
dictionary[valueName] = fieldValue;
95+
dictionary[name] = fieldValue;
9496
if (field.GetCustomAttribute<EnumMemberAttribute>()?.Value is { } enumMember)
9597
{
9698
dictionary[enumMember] = fieldValue;
9799
}
98100
}
99101

100102
return dictionary;
101-
});
102-
103-
if (enumValues.TryGetValue(value, out var enumValue))
104-
{
105-
return (TEnum)enumValue;
106103
}
104+
}
107105

108-
var defaultEnumAttribute = typeof(TEnum).GetCustomAttribute<DefaultEnumValueAttribute>();
109-
if (defaultEnumAttribute != null)
106+
private static class EnumToString<TEnum>
107+
where TEnum : struct, Enum
108+
{
109+
public static readonly IReadOnlyDictionary<TEnum, string> Cache = Compute();
110+
111+
private static Dictionary<TEnum, string> Compute()
110112
{
111-
return (TEnum)(object)defaultEnumAttribute.Value;
112-
}
113+
var names = GetNames<TEnum>();
114+
var dictionary = new Dictionary<TEnum, string>();
115+
foreach (var name in names)
116+
{
117+
var field = typeof(TEnum).GetField(name);
118+
var valueName = field.GetCustomAttribute<EnumMemberAttribute>()?.Value ?? name;
119+
var fieldValue = (TEnum)field.GetValue(null);
120+
dictionary[fieldValue] = valueName;
121+
}
113122

114-
throw new ArgumentException($"Unknown value '{value}' for enum {typeof(TEnum).Name}");
123+
return dictionary;
124+
}
115125
}
116126
}

0 commit comments

Comments
 (0)