开发者

Custom C# Enum ToString() when generated dynamically

开发者 https://www.devze.com 2023-04-12 18:59 出处:网络
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.

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 re开发者_如何学Cpresents 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?


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


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.


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


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

}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号