From eb0f05ed6af0913562dd3c5be1415233f8b7f4e7 Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Tue, 7 Apr 2020 11:58:43 +0100 Subject: [PATCH 1/6] Add flag enum support Fixes #8 --- src/EnumDisplayName/EnumExtensions.cs | 80 ++++++++++++--- .../EnumExtensionsGetFlagsDisplayNameTests.cs | 99 +++++++++++++++++++ .../Enums/MockFlagEnum.cs | 25 +++++ 3 files changed, 193 insertions(+), 11 deletions(-) create mode 100644 test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs create mode 100644 test/EnumDisplayName.Test/Enums/MockFlagEnum.cs diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 85d1f1f..443f4b5 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -1,9 +1,13 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; #if NETSTANDARD1_3 + using System.Reflection; + #endif namespace Enable.EnumDisplayName @@ -35,26 +39,80 @@ public static string GetDisplayName(this Enum enumValue) if (string.Compare(fieldName, field.Name, StringComparison.Ordinal) == 0) { - var customAttributes = field.GetCustomAttributes(false); - var enumDisplayNameAttribute = customAttributes.OfType().FirstOrDefault(); + var fieldAttributes = field.GetCustomAttributes(false).Cast(); + return GetNameFromEnumField(enumValue, fieldAttributes); + } + } - if (enumDisplayNameAttribute != null) - { - return enumDisplayNameAttribute.GetDisplayName(); - } + return string.Empty; + } + + /// + /// Returns the display names of a flag enum as a comma seperated string as specified by the + /// EnumDisplayNameAttribute declared on the enum field. If no EnumDisplayNameAttribute is + /// declared on the enum field then the name of the enum field is returned. + /// + public static string GetFlagsDisplayName(this Enum enumValue) + { + if (enumValue == null) + { + return string.Empty; + } - var displayNameAttribute = customAttributes.OfType().FirstOrDefault(); + var enumType = enumValue.GetType(); + var fieldNames = Enum.GetNames(enumType); + var fields = enumType.GetFields() + .Where(o => fieldNames.Any(p => p == o.Name)) + .ToArray(); - if (displayNameAttribute != null) + var fieldPosition = 0; + var result = string.Empty; + foreach (Enum currentValue in Enum.GetValues(enumType)) + { + if (enumValue.HasFlag(currentValue)) + { + var currentField = fields[fieldPosition]; + if (currentField.IsSpecialName) { - return displayNameAttribute.GetName(); + fieldPosition += 1; + continue; } - return fieldName; + var fieldAttributes = currentField + .GetCustomAttributes(false) + .Cast(); + + var fieldName = GetNameFromEnumField(enumValue, fieldAttributes); + + result = result == string.Empty ? fieldName + : result + "," + fieldName; } + + fieldPosition += 1; } - return string.Empty; + return result; + } + + private static string GetNameFromEnumField(Enum enumValue, IEnumerable fieldAttributes) + { + var enumType = enumValue.GetType(); + var fieldName = Enum.GetName(enumType, enumValue); + var enumDisplayNameAttribute = fieldAttributes.OfType().FirstOrDefault(); + + if (enumDisplayNameAttribute != null) + { + return enumDisplayNameAttribute.GetDisplayName(); + } + + var displayNameAttribute = fieldAttributes.OfType().FirstOrDefault(); + + if (displayNameAttribute != null) + { + return displayNameAttribute.GetName(); + } + + return fieldName; } } } diff --git a/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs b/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs new file mode 100644 index 0000000..16cc259 --- /dev/null +++ b/test/EnumDisplayName.Test/EnumExtensionsGetFlagsDisplayNameTests.cs @@ -0,0 +1,99 @@ +using System; +using Xunit; + +namespace Enable.EnumDisplayName +{ + public class EnumExtensionsGetFlagsDisplayNameTests + { + [Fact] + public void GetFlagsDisplayName_ReturnsEmptyStringWhenSourceIsNull() + { + // Arrange + Enum source = null; + + // Act + var result = source.GetFlagsDisplayName(); + + // Assert + Assert.Equal(string.Empty, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEnumDisplayNameAttributeDisplayName() + { + // Act + var result = MockFlagEnum.EnumDisplayNameAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.EnumDisplayNameAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEnumDisplayNameAttributeWithResourceDisplayName() + { + // Act + var result = MockFlagEnum.EnumDisplayNameAttributeWithResource.GetFlagsDisplayName(); + + // Assert + Assert.Equal(Resources.MockEnum.EnumDisplayNameAttributeWithResource, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsDisplayAttributeDisplayName() + { + // Act + var result = MockFlagEnum.DisplayAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.DisplayAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsFieldName() + { + // Act + var result = MockFlagEnum.NoAttribute.GetFlagsDisplayName(); + + // Assert + Assert.Equal(MockEnumDisplayNames.NoAttribute, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsEmptyStringWithSpecialNameAttribute() + { + // Act + var result = MockFlagEnum.SpecialName.GetFlagsDisplayName(); + + // Assert + Assert.Equal(string.Empty, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsCommaSeperatedStringForFlagValues() + { + // Arrange + var sut = MockFlagEnum.DisplayAttribute | MockFlagEnum.EnumDisplayNameAttribute; + + // Act + var result = sut.GetFlagsDisplayName(); + + // Assert + var expected = $"{MockEnumDisplayNames.EnumDisplayNameAttribute},{MockEnumDisplayNames.DisplayAttribute}"; + Assert.Equal(expected, result); + } + + [Fact] + public void GetFlagsDisplayName_ReturnsCommaSeperatedStringForFlagValues_ExceptSpecialNameAttributes() + { + // Arrange + var sut = MockFlagEnum.DisplayAttribute | MockFlagEnum.SpecialName; + + // Act + var result = sut.GetFlagsDisplayName(); + + // Assert + var expected = $"{MockEnumDisplayNames.DisplayAttribute}"; + Assert.Equal(expected, result); + } + } +} diff --git a/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs b/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs new file mode 100644 index 0000000..84d3656 --- /dev/null +++ b/test/EnumDisplayName.Test/Enums/MockFlagEnum.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Runtime.CompilerServices; + +namespace Enable.EnumDisplayName +{ + [Flags] + public enum MockFlagEnum + { + [EnumDisplayName(MockEnumDisplayNames.EnumDisplayNameAttribute)] + EnumDisplayNameAttribute = 1, + + [EnumDisplayName(MockEnumDisplayNames.EnumDisplayNameAttributeWithResource, typeof(Resources.MockEnum))] + EnumDisplayNameAttributeWithResource = 2, + + [Display(Name = MockEnumDisplayNames.DisplayAttribute)] + DisplayAttribute = 4, + + NoAttribute = 8, + + [SpecialName] + [EnumDisplayName(MockEnumDisplayNames.SpecialName)] + SpecialName = 16 + } +} From 61b314d3ca1112b8d707bca22c236d4176f8f753 Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Tue, 7 Apr 2020 12:08:43 +0100 Subject: [PATCH 2/6] Tidy enum extensions --- src/EnumDisplayName/EnumExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 443f4b5..21ac496 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -5,9 +5,7 @@ using System.Linq; #if NETSTANDARD1_3 - using System.Reflection; - #endif namespace Enable.EnumDisplayName From d05226cdac2d1c7a3e241f7be1ff920bc5fd5895 Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Wed, 8 Apr 2020 19:18:08 +0100 Subject: [PATCH 3/6] Further tidying --- src/EnumDisplayName/EnumExtensions.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 21ac496..66c6156 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; @@ -37,7 +36,10 @@ public static string GetDisplayName(this Enum enumValue) if (string.Compare(fieldName, field.Name, StringComparison.Ordinal) == 0) { - var fieldAttributes = field.GetCustomAttributes(false).Cast(); + var fieldAttributes = field + .GetCustomAttributes(false) + .Cast(); + return GetNameFromEnumField(enumValue, fieldAttributes); } } @@ -96,14 +98,18 @@ private static string GetNameFromEnumField(Enum enumValue, IEnumerable().FirstOrDefault(); + var enumDisplayNameAttribute = fieldAttributes + .OfType() + .FirstOrDefault(); if (enumDisplayNameAttribute != null) { return enumDisplayNameAttribute.GetDisplayName(); } - var displayNameAttribute = fieldAttributes.OfType().FirstOrDefault(); + var displayNameAttribute = fieldAttributes + .OfType() + .FirstOrDefault(); if (displayNameAttribute != null) { From abd3637656e74ebb90ace076b99dc8d19147211f Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Wed, 8 Apr 2020 19:20:12 +0100 Subject: [PATCH 4/6] Add documentation for new method --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 78c3009..888eccc 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,16 @@ Otherwise the method will return the field name of the enum. ```c# var displayName = Enum.EnumValue.GetDisplayName(); +``` + +## EnumExtensions.GetFlagsDisplayName() + +If the EnumDisplayNameAttribute had been applied to an flag enum this method returns the display names set using this attribute in a comma seperated string. + +If the System.ComponentModel.DataAnnotations.DisplayAttribute has been applied to an enum, and the EnumDisplayNameAttribute has not been applied, this method returns the display name set using this attribute. + +Otherwise the method will return the field name of the enum. + +```c# +var displayName = (Enum.EnumValue1 | Enum.EnumValue2).GetFlagsDisplayName(); ``` \ No newline at end of file From 5980dc1a7d378dbbf4aa2d6ebc62d2e32eadb5dc Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Thu, 3 Dec 2020 17:12:05 +0000 Subject: [PATCH 5/6] Address PR feedback --- src/EnumDisplayName/EnumExtensions.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 66c6156..3d3a3ec 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Text; #if NETSTANDARD1_3 using System.Reflection; @@ -62,11 +63,11 @@ public static string GetFlagsDisplayName(this Enum enumValue) var enumType = enumValue.GetType(); var fieldNames = Enum.GetNames(enumType); var fields = enumType.GetFields() - .Where(o => fieldNames.Any(p => p == o.Name)) + .Where(o => fieldNames.Contains(o.Name, StringComparer.OrdinalIgnoreCase)) .ToArray(); var fieldPosition = 0; - var result = string.Empty; + var result = new StringBuilder(); foreach (Enum currentValue in Enum.GetValues(enumType)) { if (enumValue.HasFlag(currentValue)) @@ -84,14 +85,14 @@ public static string GetFlagsDisplayName(this Enum enumValue) var fieldName = GetNameFromEnumField(enumValue, fieldAttributes); - result = result == string.Empty ? fieldName - : result + "," + fieldName; + var resultPartToAdd = result.Length == 0 ? fieldName : "," + fieldName; + result.Append(resultPartToAdd); } fieldPosition += 1; } - return result; + return result.ToString(); } private static string GetNameFromEnumField(Enum enumValue, IEnumerable fieldAttributes) From 6e28316fc2ae3b8233563065ee7645d7dccd9d93 Mon Sep 17 00:00:00 2001 From: Michael Hancock Date: Thu, 3 Dec 2020 17:19:38 +0000 Subject: [PATCH 6/6] Change case sensitivity --- src/EnumDisplayName/EnumExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnumDisplayName/EnumExtensions.cs b/src/EnumDisplayName/EnumExtensions.cs index 3d3a3ec..e2469ec 100644 --- a/src/EnumDisplayName/EnumExtensions.cs +++ b/src/EnumDisplayName/EnumExtensions.cs @@ -63,7 +63,7 @@ public static string GetFlagsDisplayName(this Enum enumValue) var enumType = enumValue.GetType(); var fieldNames = Enum.GetNames(enumType); var fields = enumType.GetFields() - .Where(o => fieldNames.Contains(o.Name, StringComparer.OrdinalIgnoreCase)) + .Where(o => fieldNames.Contains(o.Name, StringComparer.Ordinal)) .ToArray(); var fieldPosition = 0;