如何在 C# 枚举中使用特殊字符?

发布于 2024-08-23 11:49:51 字数 125 浏览 3 评论 0原文

例如:

public enum Unit{
  KW,
  kV,
  V,
  Hz,
  %V
}

在本例中 % 是一个特殊字符。那么,如何将这个字符放入枚举中呢?

For example:

public enum Unit{
  KW,
  kV,
  V,
  Hz,
  %V
}

In this case % is a special character. So, how can I put this char in a enum?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

绳情 2024-08-30 11:49:51

即使您可以做到这一点(看起来您做不到),它也可能不是一个好主意,因为您会将枚举的显示方式与程序代码混合在一起以操作它。更好的选择是定义一个属性(或使用现有的 DisplayNameAttribute )并使用名称注释您的枚举作为附加元数据:

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

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 
} 
梦屿孤独相伴 2024-08-30 11:49:51

枚举成员不应用于用户界面显示目的。它们应该映射到一个字符串才能显示。您可以创建一个字符串数组(或字典),将每个枚举成员映射到一个字符串以供用户交互。

也就是说,要直接回答您的问题,您可以使用 \uxxxxV ,其中 xxxx 是代表 %。这远非推荐的做法。 正如 Henk 指出的,这对 % 不起作用,因为它不在 Unicode 类 Lu、Ll、Lt、Lm、Lo、Nl、Mn、Mc 中、Nd、Pc、Cf(字母、数字、连接和格式字符)。只有这些字符才可以作为标识符。

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.

甜宝宝 2024-08-30 11:49:51

只是为了注册另一种方法来做到这一点,以一种简单的方式,您可以使用常量定义“您自己的”枚举器。在您的示例中

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

要访问,只需: UnitEnum.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

绻影浮沉 2024-08-30 11:49:51

这个答案与@Coppermill 的答案相关,我觉得在使用 Enums 时使用 DescriptionAttribute 在语义上更正确

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
}

然后我像这样阅读它

    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;
    }

然后用法是 ReadDescription(ReportStatus.Running) 我还有一个方法,可以将 Enum 转换为 KeyValuePair Enumerable,以便将 Enum 绑定到 DropDown。

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.

紫南 2024-08-30 11:49:51

抱歉,我刚刚意识到我没有回答这个问题。我不会删除我的答案,因为有人可能会发现这些代码片段很有帮助。


我完全同意Tomas Petricek的观点,所以我不会重复他的回答。

这是我对问题的解决方案。我使用这段代码大约五年了。我决定创建一个自定义属性,以便将 DisplayName 属性用于标题等。


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

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
╰沐子 2024-08-30 11:49:51

枚举成员不应用于用户界面显示目的。但是您可以使用简单技巧DisplayName("Your Property Display Name")来解决这个问题,如下所示。

//Enum
public enum ErrorCodes
{
      [DisplayName("U-volt")] UVolt = 2,
      [DisplayName("L-trip")] Ltrip = 5
}


//Here you can retrive Display name as bellow
public class MyClass{
     public void readEnumDisplayName(){
         String ErroCode = Enum.GetName(typeof(ErrorCodes), 5);    // Find Error Name using Integer value
          MemberInfo property = typeof(ErrorCodes).GetRuntimeField(ErroCode);     //Find Field
          var dd = property.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute;   //Find Display Attribute
          if (dd != null)  //Check if null
          {
             var name = dd.DisplayName;   //Retrive Display name
          }
      }
}

Enum members shouldn't be used for user interface display purposes. But you can use simple tricks with DisplayName("Your Property Display Name") for this matter as bellow.

//Enum
public enum ErrorCodes
{
      [DisplayName("U-volt")] UVolt = 2,
      [DisplayName("L-trip")] Ltrip = 5
}


//Here you can retrive Display name as bellow
public class MyClass{
     public void readEnumDisplayName(){
         String ErroCode = Enum.GetName(typeof(ErrorCodes), 5);    // Find Error Name using Integer value
          MemberInfo property = typeof(ErrorCodes).GetRuntimeField(ErroCode);     //Find Field
          var dd = property.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute;   //Find Display Attribute
          if (dd != null)  //Check if null
          {
             var name = dd.DisplayName;   //Retrive Display name
          }
      }
}
落日海湾 2024-08-30 11:49:51

有些人可能会说枚​​举仅用于代码,我必须不同意,我使用代码和显示功能。

在您的特定情况下,我会使用完整的单词

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

,因此我可以在下拉列表中使用它们,例如(当我需要创建一个新项目时,我需要做的就是将该项目附加到枚举中......

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

我倾向于使用空格分隔符,但我通常使用下划线来制作空格,就像

public enum myType { Process_Time, Process_Order, Process_Invoices }

DropDownList 项一样,

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

当我想从 DropDown 设置类型时,我当然会使用解析

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

,如果您使用分隔符

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

一些规则考虑编写更好的代码

  • 始终将 Type 写入 Enum,在您的情况下 Unit 应为 UnitType
  • 对枚举对象使用标题大小写

作为提醒

  • 您可以在位操作中使用枚举添加 [Flags] 关键字
  • 如果您不想使用枚举,则可以指定枚举的整数值:0、1、2、3...

我可以帮助某人。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文