动态生成时的自定义 C# Enum ToString()

发布于 2024-12-09 13:08:22 字数 1895 浏览 0 评论 0原文

我在 C# ASP.NET 解决方案中生成代表数据库中整数 ID 的动态枚举。我想要两件事,尽管两者都不可能实现。

1)我希望 .ToString() 方法给我“345”,例如,而不是枚举的字符串名称(它表示为字符串的 int)。这个问题的每个答案似乎都添加

[Description="Blah"]
EnumName = 1

在声明上方并使用 GetDescription() 方法。我不知道如何使用我正在使用的动态代码来做到这一点。

2)我宁愿不强制转换为 int 来使用它,例如我宁愿使用 (Enum.Name == 5) 。如果这是不可能的,我会进行强制转换,但我真的不想使用 ((int)Enum.Name)).ToString();

这是动态代码生成:

public static void Main()
{
    AppDomain domain = AppDomain.CurrentDomain;

    AssemblyName aName = new AssemblyName("DynamicEnums");
    AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

    ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

    List<Type> types = new List<Type>();

    foreach(ReferenceType rt in GetTypes())
    {
        EnumBuilder eb = mb.DefineEnum(rt.Name, TypeAttributes.Public, typeof(int));

        foreach (Reference r in GetReferences(rt.ID))
        {
            eb.DefineLiteral(NameFix(r.Name), r.ID);
        }

        types.Add(eb.CreateType());
    }

    ab.Save(aName.Name + ".dll");

    foreach (Type t in types)
    {
        foreach (object o in Enum.GetValues(t))
        {
            Console.WriteLine("{0}.{1} = {2}", t, o, ((int) o));
        }

        Console.WriteLine();
        //Console.ReadKey();
    }

    Console.WriteLine();
    Console.WriteLine("Dynamic Enums Built Successfully.");
}

public static string NameFix(string name)
{
    //Strip all non alphanumeric characters
    string r = Regex.Replace(name, @"[^\w]", "");

    //Enums cannot begin with a number
    if (Regex.IsMatch(r, @"^\d"))
        r = "N" + r;

    return r;
}

可能没有办法做我想做的事情,并且我会陷入困境:

(int)Countries.USA //For int value
((int)Countries.CAN).ToString() //For string representation of int value, ex. "354"

有什么想法吗?

I generate dynamic enums that represent integer IDs from my database in a C# ASP.NET solution. I would like two things, although neither may be possible.

1) I want the .ToString() method to give me "345" for example, not the string name of the enum (the int it represents as a string). Every answer to this question seems to be adding

[Description="Blah"]
EnumName = 1

above the declaration and using a GetDescription() method. I have no idea how to do this with the dynamic code that I am using.

2) I'd rather not cast to an int to use it as such, I'd rather (Enum.Name == 5) for example. If this isn't possible I'll cast, but I really don't want to use ((int)Enum.Name)).ToString();

Here's the dynamic code generation:

public static void Main()
{
    AppDomain domain = AppDomain.CurrentDomain;

    AssemblyName aName = new AssemblyName("DynamicEnums");
    AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);

    ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

    List<Type> types = new List<Type>();

    foreach(ReferenceType rt in GetTypes())
    {
        EnumBuilder eb = mb.DefineEnum(rt.Name, TypeAttributes.Public, typeof(int));

        foreach (Reference r in GetReferences(rt.ID))
        {
            eb.DefineLiteral(NameFix(r.Name), r.ID);
        }

        types.Add(eb.CreateType());
    }

    ab.Save(aName.Name + ".dll");

    foreach (Type t in types)
    {
        foreach (object o in Enum.GetValues(t))
        {
            Console.WriteLine("{0}.{1} = {2}", t, o, ((int) o));
        }

        Console.WriteLine();
        //Console.ReadKey();
    }

    Console.WriteLine();
    Console.WriteLine("Dynamic Enums Built Successfully.");
}

public static string NameFix(string name)
{
    //Strip all non alphanumeric characters
    string r = Regex.Replace(name, @"[^\w]", "");

    //Enums cannot begin with a number
    if (Regex.IsMatch(r, @"^\d"))
        r = "N" + r;

    return r;
}

There may just be no way to do what I want to do, and I'll be stuck using:

(int)Countries.USA //For int value
((int)Countries.CAN).ToString() //For string representation of int value, ex. "354"

Any ideas?

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

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

发布评论

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

评论(4

护你周全 2024-12-16 13:08:23

我意识到该问题已被标记为已回答,但也许使用扩展可能有用?

它仍然允许您以这种方式使用生成的枚举。

附:调用 GetString 时要小心 - 不要意外地调用 ToString!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApplication1
{

    public enum YourEnum
    {
        Apples = 1,
        Pears = 2,
    }

    class Program
    {
        static void Main(string[] args)
        {
            foreach (var value in (YourEnum[])Enum.GetValues(typeof(YourEnum)))
            {
                int v = value.GetValue();
                Console.WriteLine("{0} = {1} (int)", value.ToString(), v);

                string s = value.GetString();
                Console.WriteLine("{0} = {1} (string)", value.ToString(), s);
            }
            Console.ReadLine();

            //Results:

            //Apples = 1 (int)
            //Apples = 1 (string)
            //Pears = 2 (int)
            //Pears = 2 (string)
        }
    }

    public static class EnumExtensions
    {
        public static int GetValue(this Enum value) 
        {
            return Convert.ToInt32(value);
        }

        public static string GetString(this Enum value)
        {
            return Convert.ToInt32(value).ToString();
        }
    }

}

I realise that the question has been marked as answered, but perhaps using an extension might be useful?

It still allows you to use your generated enums this way.

ps. Take care when calling GetString - don't accidentally call ToString instead!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApplication1
{

    public enum YourEnum
    {
        Apples = 1,
        Pears = 2,
    }

    class Program
    {
        static void Main(string[] args)
        {
            foreach (var value in (YourEnum[])Enum.GetValues(typeof(YourEnum)))
            {
                int v = value.GetValue();
                Console.WriteLine("{0} = {1} (int)", value.ToString(), v);

                string s = value.GetString();
                Console.WriteLine("{0} = {1} (string)", value.ToString(), s);
            }
            Console.ReadLine();

            //Results:

            //Apples = 1 (int)
            //Apples = 1 (string)
            //Pears = 2 (int)
            //Pears = 2 (string)
        }
    }

    public static class EnumExtensions
    {
        public static int GetValue(this Enum value) 
        {
            return Convert.ToInt32(value);
        }

        public static string GetString(this Enum value)
        {
            return Convert.ToInt32(value).ToString();
        }
    }

}
无力看清 2024-12-16 13:08:22

您可以调整类型安全的枚举模式来满足您的需要吗?

public class MyEnum
{
    #region Enum Values

    // Pre defined values.    
    public static readonly MyEnum ValueOne = new MyEnum(0);
    public static readonly MyEnum ValueTwo = new MyEnum(1);

    // All values in existence.
    private static readonly Dictionary<int, MyEnum> existingEnums = new Dictionary<int, MyEnum>{{ValueOne.Value, ValueOne}, {ValueTwo.Value, ValueTwo}};

    #endregion

    #region Enum Functionality

    private readonly int Value;

    private MyEnum(int value)
    {
        Value = value;
    }

    public static MyEnum GetEnum(int value)
    {
        // You will probably want to make this thread-safe.
        if (!existingEnums.ContainsKey(value)) existingEnums[value] = new MyEnum(value);

        return existingEnums[value];
    }

    public override string ToString()
    {
        return Value.ToString();
    }

    #endregion
}

用法:

private void Foo(MyEnum enumVal)
{
  return "Enum Value: " + enumVal;  // returns "Enum Value: (integer here) 
}

或:

MyEnum.GetValue(2) == MyEnum.GetValue(4); // false
MyEnum.GetValue(3) == MyEnum.GetValue(3); // true

Could you adapt the type-safe enum pattern to do what you need?

public class MyEnum
{
    #region Enum Values

    // Pre defined values.    
    public static readonly MyEnum ValueOne = new MyEnum(0);
    public static readonly MyEnum ValueTwo = new MyEnum(1);

    // All values in existence.
    private static readonly Dictionary<int, MyEnum> existingEnums = new Dictionary<int, MyEnum>{{ValueOne.Value, ValueOne}, {ValueTwo.Value, ValueTwo}};

    #endregion

    #region Enum Functionality

    private readonly int Value;

    private MyEnum(int value)
    {
        Value = value;
    }

    public static MyEnum GetEnum(int value)
    {
        // You will probably want to make this thread-safe.
        if (!existingEnums.ContainsKey(value)) existingEnums[value] = new MyEnum(value);

        return existingEnums[value];
    }

    public override string ToString()
    {
        return Value.ToString();
    }

    #endregion
}

Usage:

private void Foo(MyEnum enumVal)
{
  return "Enum Value: " + enumVal;  // returns "Enum Value: (integer here) 
}

Or:

MyEnum.GetValue(2) == MyEnum.GetValue(4); // false
MyEnum.GetValue(3) == MyEnum.GetValue(3); // true
囚我心虐我身 2024-12-16 13:08:22

那么您实际上想要将 Enum 值转换为 string 而不是名称?转换为 Enum 的基础类型是获取值的最简单方法。我认为您将很难找到比 ((int)...) 更短或更简单的内容。

如果您不想“枚举”某些值,或者想做一些不同的事情,您可以创建自己的 YourEnum 类,它基本上内置了强制转换,在需要时进行强制转换似乎更容易且更具可读性。

也许您实际上想要一些常量。

const string Blah = "345";

编辑

我有另一个想法,你可以为Enum编写一个扩展方法,如下所示,

public static class MyExtentions
{
    public static string ValueString(this Enum e)
    {
       var ut = Enum.GetUnderlyingType(e.GetType());
       var castToString = typeOf(MyExtentions).GetMethod("CastToString");
       var gcast = cast.MakeGenericMethod(ut);
       var gparams = new object[] {e};
       return gcast.Invoke(null, gparams).ToString();
    }

    public static string CastToString<T>(object o)
    {
        return ((T)o).ToString();
    }

}

有了这个,你可以在任何<上调用ValueString() code>Enum 实例并获取值的字符串。它显然使用了反射,因此性能不会令人惊叹,但我认为这对您的情况并不重要。

So you actually want to convert the Enum value to a string not the name? Casting to the Enum's underlying type is the simplest way to get the value out. I think you will struggle to get anything shorter or simpler than ((int)...).

If you don't want to "enumerate" some values, or want to do somthing different you could make your own class of YourEnum which basically has the cast built in, casting when required seems easier and more readable.

Perhaps you actually want some constants.

const string Blah = "345";

EDIT

I had another idea, you could write an extension method for Enum like this,

public static class MyExtentions
{
    public static string ValueString(this Enum e)
    {
       var ut = Enum.GetUnderlyingType(e.GetType());
       var castToString = typeOf(MyExtentions).GetMethod("CastToString");
       var gcast = cast.MakeGenericMethod(ut);
       var gparams = new object[] {e};
       return gcast.Invoke(null, gparams).ToString();
    }

    public static string CastToString<T>(object o)
    {
        return ((T)o).ToString();
    }

}

With this you can call ValueString() on any Enum instance and get a string of the value. It clearly used reflection so the performance won't be amazing but I don't think that matters in your case.

亚希 2024-12-16 13:08:22

当您使用 Enum 类类型时,如何使用 Enum.Format 方法。

例如:

enum EnumClassA {One, Two, Three, Four};

...

EnumClassA chosenValue = EnumClassA.Three;

Console.WriteLine("Chosen value is {0}", Enum.Format(typeof(EnumClassA), chosenValue, "d"));

这应该给出一个输出:

Chosen value is 2

edit

另一种选择是:

EnumClassA.Three.ToString("d"); //Enum.Name.ToString("d")

这也给出了字符串值“2”。

** 编辑 **

当您进行比较以查看枚举中是否存在该值时,如何使用返回 bool 的 Enum.IsDefined(enumType, value) ?

Console.WriteLine("Does the enumClassA contain {0} result is {1}", 5, Enum.IsDefined(typeof(enumClassA), 5));

输出为:

Does the enumClassA contain 5 result is False

As you're using the Enum class type, how about using the Enum.Format method.

For example:

enum EnumClassA {One, Two, Three, Four};

...

EnumClassA chosenValue = EnumClassA.Three;

Console.WriteLine("Chosen value is {0}", Enum.Format(typeof(EnumClassA), chosenValue, "d"));

This should give an output of:

Chosen value is 2

edit

Another option would be:

EnumClassA.Three.ToString("d"); //Enum.Name.ToString("d")

This also gives a string value of "2".

** edit **

As you're doing comparisons to see if the value exists within your enums how about using Enum.IsDefined(enumType, value) which returns a bool?

Console.WriteLine("Does the enumClassA contain {0} result is {1}", 5, Enum.IsDefined(typeof(enumClassA), 5));

This gives an output of:

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