Пользовательский C # Enum ToString () при динамическом генерировании - PullRequest
1 голос
/ 14 октября 2011

Я генерирую динамические перечисления, которые представляют целочисленные идентификаторы из моей базы данных в решении C # ASP.NET.Я хотел бы две вещи, хотя ни одна из них не может быть возможной.

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"

Есть идеи?

Ответы [ 4 ]

3 голосов
/ 14 октября 2011

То есть вы действительно хотите преобразовать значение Enum в string, а не в имя? Приведение к базовому типу Enum - это самый простой способ получить значение. Я думаю, вы будете бороться, чтобы получить что-нибудь короче или проще, чем ((int)...).

Если вы не хотите «перечислять» некоторые значения или хотите делать что-то другое, вы можете сделать свой собственный класс YourEnum, который в основном имеет встроенное приведение, приведение при необходимости кажется более простым и читаемым.

Возможно, вам действительно нужны константы.

const string Blah = "345";

EDIT

У меня была другая идея, вы могли бы написать метод расширения для 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() для любого Enum экземпляра и получить строку значения. Он явно использовал отражение, поэтому производительность не будет удивительной, но я не думаю, что это имеет значение в вашем случае.

3 голосов
/ 14 октября 2011

Не могли бы вы адаптировать шаблон enum для безопасного типа, чтобы сделать то, что вам нужно?

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
2 голосов
/ 14 октября 2011

Я понимаю, что вопрос был помечен как ответ, но, возможно, использование расширения может быть полезным?

Это все еще позволяет вам использовать сгенерированные перечисления таким образом.

пс. Будьте осторожны при вызове 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();
        }
    }

}
2 голосов
/ 14 октября 2011

Поскольку вы используете тип класса 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".

** edit **

Когда вы проводите сравнения, чтобы увидеть, существует ли значение в ваших перечислениях, как насчет использования Enum.IsDefined (enumType, value), который возвращает bool?

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

Это дает вывод:

Does the enumClassA contain 5 result is False
...