1515namespace Open . Text ;
1616
1717/// <summary>
18- /// A case struct representing an enum value that can be implicitly coerced from a string.
18+ /// A struct representing an enum value that can be implicitly coerced from a string.
1919/// </summary>
2020/// <remarks>String parsing or coercion is case sensitive and must be exact.</remarks>
2121[ SuppressMessage ( "Usage" , "CA2225:Operator overloads have named alternates" , Justification = "Already exposes via a property." ) ]
2222[ SuppressMessage ( "Design" , "CA1000:Do not declare static members on generic types" , Justification = "Intentional" ) ]
23+ [ SuppressMessage ( "Roslynator" , "RCS1158:Static member in generic type should use a type parameter." ) ]
2324[ DebuggerDisplay ( "{GetDebuggerDisplay()}" ) ]
2425public readonly struct EnumValue < TEnum >
2526 : IEquatable < EnumValue < TEnum > > , IEquatable < EnumValueCaseIgnored < TEnum > > , IEquatable < TEnum >
@@ -34,29 +35,25 @@ public readonly struct EnumValue<TEnum>
3435 public static Type UnderlyingType => _underlyingType ??= Enum . GetUnderlyingType ( typeof ( TEnum ) ) ;
3536
3637 /// <summary>
37- /// Constructs an EnumValue<<typeparamref name=" TEnum"/>> using the provided enum value.
38+ /// Constructs an <see cref="EnumValue{ TEnum} "/> using the provided <typeparamref name="TEnum"/> value.
3839 /// </summary>
3940 public EnumValue ( TEnum value )
40- {
41- Value = value ;
42- }
41+ => Value = value ;
4342
4443 /// <summary>
45- /// Parses the string value to construct an EnumValue<<typeparamref name=" TEnum"/>> instance .
44+ /// Parses the <paramref name=" value"/> to construct an <see cref="EnumValue{ TEnum} "/>.
4645 /// </summary>
4746 /// <exception cref="ArgumentNullException">value is null.</exception>
4847 public EnumValue ( StringSegment value )
49- {
50- Value = EnumValue . Parse < TEnum > ( value ) ;
51- }
48+ => Value = EnumValue . Parse < TEnum > ( value ) ;
5249
5350 /// <summary>
54- /// The enum value that this represents.
51+ /// The <typeparamref name="TEnum"/> value that this represents.
5552 /// </summary>
5653 public readonly TEnum Value { get ; }
5754
5855 /// <summary>
59- /// Returns the string representation of the enum value.
56+ /// Returns the <see cref=" string"/> representation of the enum value.
6057 /// </summary>
6158 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
6259 public override string ToString ( ) => NameLookup ( Value ) ;
@@ -165,7 +162,18 @@ internal static Func<string, ValueLookupResult> ValueLookup
165162 private static IReadOnlyDictionary < string , TEnum > ? _ignoreCaseLookup ;
166163 internal static IReadOnlyDictionary < string , TEnum > IgnoreCaseLookup
167164 => LazyInitializer . EnsureInitialized ( ref _ignoreCaseLookup ,
168- ( ) => Values . ToDictionary ( e => Enum . GetName ( typeof ( TEnum ) , e ) ! , e => e , StringComparer . OrdinalIgnoreCase ) ) ! ;
165+ ( ) =>
166+ {
167+ // If the enum has duplicate values, we want to use the first one.
168+ var result = new Dictionary < string , TEnum > ( StringComparer . OrdinalIgnoreCase ) ;
169+ foreach ( var e in Values )
170+ {
171+ var v = Enum . GetName ( typeof ( TEnum ) , e ) ;
172+ if ( result . ContainsKey ( v ) ) continue ;
173+ result [ v ] = e ;
174+ }
175+ return result ;
176+ } ) ! ;
169177
170178 static Entry [ ] ? [ ] CreateLookup ( )
171179 {
@@ -242,7 +250,6 @@ public static int Find(Span<Entry> span, ReadOnlySpan<char> name, StringComparis
242250 return middle ;
243251 }
244252
245-
246253 return - 1 ;
247254 }
248255 }
@@ -253,49 +260,58 @@ internal static Entry[]?[] Lookup
253260 ( ) => CreateLookup ( ) ) ! ;
254261
255262 /// <summary>
256- /// Indicates whether this instance matches the enum value of <paramref name="other"/>.
263+ /// Indicates whether this instance matches the <typeparamref name="TEnum"/> value of <paramref name="other"/>.
257264 /// </summary>
258- /// <returns>true if <paramref name="other"/>'s enum value and this instance's enum value are the same; otherwise false.</returns>
259- public bool Equals ( EnumValue < TEnum > other ) => Value . Equals ( other . Value ) ;
265+ /// <returns>true if <paramref name="other"/>'s <typeparamref name="TEnum"/> value and this instance's <typeparamref name="TEnum"/> value are the same; otherwise false.</returns>
266+ public bool Equals ( EnumValue < TEnum > other )
267+ => Value . Equals ( other . Value ) ;
260268
261269 /// <summary>
262- /// Compares an EnumValue and EnumValueCaseIgnored for enum equality.
270+ /// Compares an <see cref=" EnumValue{TEnum}"/> and <see cref=" EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> equality.
263271 /// </summary>
264- public static bool operator == ( EnumValue < TEnum > left , EnumValue < TEnum > right ) => left . Value . Equals ( right . Value ) ;
272+ public static bool operator == ( EnumValue < TEnum > left , EnumValue < TEnum > right )
273+ => left . Value . Equals ( right . Value ) ;
265274
266275 /// <summary>
267- /// Compares an EnumValue and EnumValueCaseIgnored for enum inequality.
276+ /// Compares an <see cref=" EnumValue{TEnum}"/> and <see cref=" EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
268277 /// </summary>
269- public static bool operator != ( EnumValue < TEnum > left , EnumValue < TEnum > right ) => ! left . Value . Equals ( right . Value ) ;
278+ public static bool operator != ( EnumValue < TEnum > left , EnumValue < TEnum > right )
279+ => ! left . Value . Equals ( right . Value ) ;
270280
271281 /// <inheritdoc cref="Equals(EnumValue{TEnum})"/>
272- public bool Equals ( EnumValueCaseIgnored < TEnum > other ) => Value . Equals ( other . Value ) ;
282+ public bool Equals ( EnumValueCaseIgnored < TEnum > other )
283+ => Value . Equals ( other . Value ) ;
273284
274285 /// <summary>
275- /// Compares two EnumValue for enum equality.
286+ /// Compares two <see cref=" EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> equality.
276287 /// </summary>
277- public static bool operator == ( EnumValue < TEnum > left , EnumValueCaseIgnored < TEnum > right ) => left . Value . Equals ( right . Value ) ;
288+ public static bool operator == ( EnumValue < TEnum > left , EnumValueCaseIgnored < TEnum > right )
289+ => left . Value . Equals ( right . Value ) ;
278290
279291 /// <summary>
280- /// Compares two EnumValue for enum inequality.
292+ /// Compares two <see cref=" EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
281293 /// </summary>
282- public static bool operator != ( EnumValue < TEnum > left , EnumValueCaseIgnored < TEnum > right ) => ! left . Value . Equals ( right . Value ) ;
294+ public static bool operator != ( EnumValue < TEnum > left , EnumValueCaseIgnored < TEnum > right )
295+ => ! left . Value . Equals ( right . Value ) ;
283296
284297 /// <summary>
285298 /// Indicates whether this instance matches the provided enum <paramref name="other"/>.
286299 /// </summary>
287300 /// <returns>true if <paramref name="other"/> and this instance's enum value are the same; otherwise false.</returns>
288- public bool Equals ( TEnum other ) => Value . Equals ( other ) ;
301+ public bool Equals ( TEnum other )
302+ => Value . Equals ( other ) ;
289303
290304 /// <summary>
291- /// Compares an EnumValue and an enum value for enum equality .
305+ /// Compares an <see cref=" EnumValue{TEnum}"/> and a <typeparamref name="TEnum"/> value forequality .
292306 /// </summary>
293- public static bool operator == ( EnumValue < TEnum > left , TEnum right ) => left . Value . Equals ( right ) ;
307+ public static bool operator == ( EnumValue < TEnum > left , TEnum right )
308+ => left . Value . Equals ( right ) ;
294309
295310 /// <summary>
296- /// Compares an EnumValue and an enum value for enum inequality.
311+ /// Compares an <see cref=" EnumValue{TEnum}"/> and a <typeparamref name="TEnum"/> value for inequality.
297312 /// </summary>
298- public static bool operator != ( EnumValue < TEnum > left , TEnum right ) => ! left . Value . Equals ( right ) ;
313+ public static bool operator != ( EnumValue < TEnum > left , TEnum right )
314+ => ! left . Value . Equals ( right ) ;
299315
300316 /// <inheritdoc />
301317 public override bool Equals ( object ? obj )
@@ -307,23 +323,28 @@ public override bool Equals(object? obj)
307323 public override int GetHashCode ( ) => Value . GetHashCode ( ) ;
308324
309325 /// <summary>
310- /// Implicitly converts an EnumValueCaseInsensitive to an EnumValue.
326+ /// Implicitly converts an <see cref="EnumValueCaseIgnored{TEnum}"/> to an <see cref=" EnumValue{TEnum}"/> .
311327 /// Before conversion they are already equivalent.
312328 /// </summary>
313329 public static implicit operator EnumValue < TEnum > ( EnumValueCaseIgnored < TEnum > value ) => new ( value . Value ) ;
314330
315331 /// <summary>
316- /// Implicitly returns the actual enum contained by the EnumValue.
332+ /// Implicitly returns the actual enum contained by the <see cref=" EnumValue{TEnum}"/> .
317333 /// </summary>
318334 public static implicit operator TEnum ( EnumValue < TEnum > value ) => value . Value ;
319335
320336 /// <summary>
321- /// Implicitly converts an string to an EnumValue of enum type TEnum.
337+ /// Implicitly converts an <typeparamref name="TEnum"/> to an <see cref="EnumValue{TEnum}"/>.
338+ /// </summary>
339+ public static implicit operator EnumValue < TEnum > ( TEnum value ) => new ( value ) ;
340+
341+ /// <summary>
342+ /// Implicitly converts a <see cref="string"/> to an <see cref="EnumValue{TEnum}"/>.
322343 /// </summary>
323344 public static implicit operator EnumValue < TEnum > ( StringSegment value ) => new ( value ) ;
324345
325346 /// <summary>
326- /// Implicitly converts an string to an EnumValue of enum type TEnum.
347+ /// Implicitly converts a <see cref=" string"/> to an <see cref="EnumValue{ TEnum}"/> .
327348 /// </summary>
328349 public static implicit operator EnumValue < TEnum > ( string value ) => new ( value ) ;
329350
@@ -374,21 +395,15 @@ public readonly struct EnumValueCaseIgnored<TEnum>
374395 where TEnum : Enum
375396{
376397 /// <summary>
377- /// Constructs an EnumValueCaseIgnored<<typeparamref name=" TEnum"/>> using the provided enum value.
398+ /// Constructs an <see cref="EnumValueCaseIgnored{ TEnum} "/> using the provided enum value.
378399 /// </summary>
379- public EnumValueCaseIgnored ( TEnum value )
380- {
381- Value = value ;
382- }
400+ public EnumValueCaseIgnored ( TEnum value ) => Value = value ;
383401
384402 /// <summary>
385- /// Parses the string value to construct an EnumValueCaseIgnored<<typeparamref name=" TEnum"/>> instance.
403+ /// Parses the string value to construct an <see cref="EnumValueCaseIgnored{ TEnum} "/> instance.
386404 /// </summary>
387405 /// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
388- public EnumValueCaseIgnored ( StringSegment value )
389- {
390- Value = EnumValue . Parse < TEnum > ( value , true ) ;
391- }
406+ public EnumValueCaseIgnored ( StringSegment value ) => Value = EnumValue . Parse < TEnum > ( value , true ) ;
392407
393408 /// <inheritdoc cref="EnumValue{TEnum}.Value"/>
394409 public readonly TEnum Value { get ; }
@@ -400,12 +415,12 @@ public EnumValueCaseIgnored(StringSegment value)
400415 public bool Equals ( EnumValue < TEnum > other ) => Value . Equals ( other . Value ) ;
401416
402417 /// <summary>
403- /// Compares an EnumValueCaseIgnored and EnumValue for enum equality.
418+ /// Compares an <see cref=" EnumValueCaseIgnored{TEnum}"/> and <see cref=" EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> equality.
404419 /// </summary>
405420 public static bool operator == ( EnumValueCaseIgnored < TEnum > left , EnumValue < TEnum > right ) => left . Value . Equals ( right . Value ) ;
406421
407422 /// <summary>
408- /// Compares an EnumValueCaseIgnored and EnumValue for enum inequality.
423+ /// Compares an <see cref=" EnumValueCaseIgnored{TEnum}"/> and <see cref=" EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
409424 /// </summary>
410425 public static bool operator != ( EnumValueCaseIgnored < TEnum > left , EnumValue < TEnum > right )
411426 => ! left . Value . Equals ( right . Value ) ;
@@ -415,13 +430,13 @@ public bool Equals(EnumValueCaseIgnored<TEnum> other)
415430 => Value . Equals ( other . Value ) ;
416431
417432 /// <summary>
418- /// Compares two EnumValueCaseIgnored for enum equality.
433+ /// Compares two <see cref=" EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> equality.
419434 /// </summary>
420435 public static bool operator == ( EnumValueCaseIgnored < TEnum > left , EnumValueCaseIgnored < TEnum > right )
421436 => left . Value . Equals ( right . Value ) ;
422437
423438 /// <summary>
424- /// Compares two EnumValueCaseIgnored for enum inequality.
439+ /// Compares two <see cref=" EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
425440 /// </summary>
426441 public static bool operator != ( EnumValueCaseIgnored < TEnum > left , EnumValueCaseIgnored < TEnum > right )
427442 => ! left . Value . Equals ( right . Value ) ;
@@ -431,13 +446,13 @@ public bool Equals(TEnum other)
431446 => Value . Equals ( other ) ;
432447
433448 /// <summary>
434- /// Compares an EnumValueCaseIgnored and an enum value for enum equality.
449+ /// Compares an <see cref=" EnumValueCaseIgnored{TEnum}"/> and a <typeparamref name="TEnum"/> value for equality.
435450 /// </summary>
436451 public static bool operator == ( EnumValueCaseIgnored < TEnum > left , TEnum right )
437452 => left . Value . Equals ( right ) ;
438453
439454 /// <summary>
440- /// Compares an EnumValueCaseIgnored and an enum value for enum inequality.
455+ /// Compares an <see cref=" EnumValueCaseIgnored{TEnum}"/> and a <typeparamref name="TEnum"/> value for inequality.
441456 /// </summary>
442457 public static bool operator != ( EnumValueCaseIgnored < TEnum > left , TEnum right )
443458 => ! left . Value . Equals ( right ) ;
@@ -453,34 +468,40 @@ public override int GetHashCode()
453468 => Value . GetHashCode ( ) ;
454469
455470 /// <summary>
456- /// Implicitly converts an EnumValue to an EnumValueCaseInsensitive .
471+ /// Implicitly converts an <see cref=" EnumValue{TEnum}"/> to an <see cref="EnumValueCaseIgnored{TEnum}"/> .
457472 /// Before conversion they are already equivalent.
458473 /// </summary>
459474 public static implicit operator EnumValueCaseIgnored < TEnum > ( EnumValue < TEnum > value )
460475 => new ( value . Value ) ;
461476
462477 /// <summary>
463- /// Implicitly returns the actual enum contained by the EnumValueCaseIgnored.
478+ /// Implicitly returns the actual <typeparamref name="TEnum"/> contained by the <see cref=" EnumValueCaseIgnored{TEnum}"/> .
464479 /// </summary>
465480 public static implicit operator TEnum ( EnumValueCaseIgnored < TEnum > value )
466481 => value . Value ;
467482
468483 /// <summary>
469- /// Implicitly converts an string to an EnumValueCaseIgnored of enum type TEnum.
484+ /// Implicitly converts an <typeparamref name="TEnum"/> to an <see cref="EnumValue{TEnum}"/>.
485+ /// </summary>
486+ public static implicit operator EnumValueCaseIgnored < TEnum > ( TEnum value )
487+ => new ( value ) ;
488+
489+ /// <summary>
490+ /// Implicitly converts a <see cref="string"/> to an <see cref="EnumValueCaseIgnored{TEnum}"/>.
470491 /// </summary>
471492 public static implicit operator EnumValueCaseIgnored < TEnum > ( StringSegment value )
472493 => new ( value ) ;
473494
474495 /// <summary>
475- /// Implicitly converts an string to an EnumValueCaseIgnored of enum type TEnum.
496+ /// Implicitly converts a <see cref=" string"/> to an <see cref="EnumValueCaseIgnored{ TEnum}"/> .
476497 /// </summary>
477498 public static implicit operator EnumValueCaseIgnored < TEnum > ( string value )
478499 => new ( value ) ;
479500
480501 private string GetDebuggerDisplay ( )
481502 {
482503 var eType = typeof ( TEnum ) ;
483- return $ "{ eType . Name } .{ Value } [EnumValueCaseIgnored<{ eType . FullName } >]";
504+ return $ "{ eType . Name } .{ ToString ( ) } [EnumValueCaseIgnored<{ eType . FullName } >]";
484505 }
485506}
486507
0 commit comments