How can I use a special char in a C# enum?

让人想犯罪 __ 提交于 2019-11-28 11:07:39

Enum members shouldn't be used for user interface display purposes. They should be mapped to a string in order to get displayed. You can create a string array (or a dictionary) that maps each enum member to a string for user interaction.

That said, to answer your question directly, you can use \uxxxxV were xxxx is the hexadecimal number representing the Unicode code point for %. This is far from recommended. As Henk points out, this won't work for % as it's not in Unicode classes Lu, Ll, Lt, Lm, Lo, Nl, Mn, Mc, Nd, Pc, Cf (letters, digits, connecting, and formatting characters). Only these characters are acceptable for identifiers.

Even if you could do that (and it looks you can't), it probably wouldn't be a good idea, because you'd be mixing how the enum should be displayed with the program code to manipulate it. A better option would be to define an attribute (or use existing DisplayNameAttribute) and annotate your enum with names as additional meta-data:

public enum Unit{ 
  [DisplayName("Hz")] Hertz, 
  [DisplayName("%V")] Volt 
} 

Just to register another way to do that, in a simple way, you can define "your own" enumerator with constants. In your example

public class UnitEnum
{
  public const string KW = "KW";
  public const string Volt = "%V";
}

To access, it just: UnitEnum.Volt

This answer is related to the one from @Coppermill I feel using the DescriptionAttribute is more semantically correct when working with Enums

public enum ReportStatus
{
    [Description("Reports that are running")] Running,
    [Description("Reports that are pending to run")] Pending,
    [Description("Reports that have errored while running")] Error,
    [Description("Report completed successfully.")] Finished
}

Then I read from it like such

    public static bool IsNullable(this Type type)
    {
        if (!type.IsGenericType)
            return false;
        var g = type.GetGenericTypeDefinition();
        return (g.Equals(typeof (Nullable<>)));
    }

    public static Type ConcreteType(this Type type)
    {
        if (IsNullable(type))
            type = UnderlyingTypeOf(type);
        return type;
    }

.

    public static string ReadDescription<T>(T enumMember)
    {
        if (typeof (T).IsNullable() && enumMember == null) return null;

        var type = (typeof (T).ConcreteType());

        var fi = type.GetField(enumMember.ToString());

        var attributes = fi.GetCustomAttributes(typeof (DescriptionAttribute), false);

        if(attributes.Length == 0) return enumMember.ToString();

        return attributes.Cast<DescriptionAttribute>().First().Description;
    }

Then usage would be ReadDescription(ReportStatus.Running) I also have a method that will convert an Enum into a KeyValuePair Enumerable for binding an Enum to a DropDown.

Coppermill

I'm not sure why you are after special characters in your enum, however if you are like me and you need to display a better name than perhaps type using the XmlEnumAttribute values for an Enum

Check out my blog for more details

http://www.bryanavery.co.uk/post/2010/01/08/How-do-you-retrieving-the-XmlEnumAttribute-values-for-an-Enum.aspx

Sorry, but I just realized that I didn't answer the question. I will not delete my answer because someone may find these code snippets helpful.


I agree completely with Tomas Petricek, so I will not repeat his answer.

Here is my solution to the problem. I been using this code for about five years. I decided to create a custom attribute in order to use the DisplayName attribute for captions and such.


Public Module MainModule
    Public Sub Main()
        Console.WriteLine(EnumEx.GetNumberFormatString(Unit.Volt), 120.13)
    End Sub
End Module

Public Enum Unit
    <NumberFormatString("{0} Hz"), DisplayName("Hertz")> Hz
    <NumberFormatString("{0} %V"), DisplayName("%Volt")> pV
End Enum

<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class NumberFormatStringAttribute
    Inherits Attribute

    Public Shared ReadOnly [Default] As NumberFormatStringAttribute = New NumberFormatStringAttribute

    Private _format As String

    Public Sub New()
        Me.New(Char.MinValue)
    End Sub

    Public Sub New(ByVal format As String)
        _format = format
    End Sub

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        If (obj Is Me) Then
            Return True
        End If
        Dim oAttribute As NumberFormatStringAttribute = TryCast(obj, NumberFormatStringAttribute)
        If (Not oAttribute Is Nothing) Then
            Return (oAttribute.NumberFormatString = Me.NumberFormatString)
        End If
        Return False
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return Me.NumberFormatString.GetHashCode
    End Function

    Public Overrides Function IsDefaultAttribute() As Boolean
        Return Me.Equals(NumberFormatStringAttribute.Default)
    End Function

    Public ReadOnly Property NumberFormatString() As String
        Get
            Return Me.NumberFormatStringValue
        End Get
    End Property

    Private Property NumberFormatStringValue() As String
        Get
            Return _format
        End Get
        Set(ByVal value As String)
            _format = value
        End Set
    End Property

End Class

Public NotInheritable Class EnumEx

    Private Sub New()
    End Sub

    Public Shared Function GetNumberFormatString(ByVal value As Object) As String
        Dim sResult As String = Nothing
        Dim oFieldInfo As System.Reflection.FieldInfo = value.GetType.GetField(value.ToString)
        If Not (oFieldInfo Is Nothing) Then
            Dim oCustomAttributes() As Object = oFieldInfo.GetCustomAttributes(GetType(NumberFormatStringAttribute), True)
            If (Not (oCustomAttributes Is Nothing)) AndAlso oCustomAttributes.Length > 0 Then
                sResult = DirectCast(oCustomAttributes(0), NumberFormatStringAttribute).NumberFormatString
            End If
        End If
        Return sResult
    End Function

End Class

Some can state that Enumerations are for Code only, I must disagree and I use to Code and Display functionality.

In your particular case I would use the full word

public enum UnitType {
  Kilowatt,
  Kilovolt,
  Volt,
  Hertz,
  Ohm,
  Faraday
}

So I can use them in a Dropdown for example as (when I need to create a new item, all I need to do is append that item into the Enumeration...

ddl.Items.Clear();
foreach (string type in Enum.GetNames(typeof(UnitType)))
    ddl.Items.Add(type);

I tend to use Space Separator, but I normally use underscore to make spaces, like

public enum myType { Process_Time, Process_Order, Process_Invoices }

and the DropDownList item would be

ddl.Items.Add(type.Replace("_", " "));

when I want to set the Type from the DropDown, I use the Parse

UnitType unit = (UnitType)Enum.Parse(
                                 typeof(UnitType),
                                 ddl.SelectedValue.toString());

off course, if you use Separator

 ddl.SelectedValue.toString().Replace(" ", "_"));

Some rules to have in consideration to write better code

  • Always write Type to an Enum, in you case Unit should be UnitType
  • Use Title Case for Enumeration Objects

As a reminder

  • You can use an Enum in a Bit Operation adding [Flags] keyword
  • You can specify the integer value of the Enum if you don't want to have: 0, 1, 2, 3...

I hope I can help someone.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!