net enum define como acceder c# database dynamic enums

define - Enum dinámico en C#



return enum c# (13)

¿Cómo creo una enumeración dinámica (y luego uso las opciones de enumeración) en C # según los valores en una tabla de búsqueda de base de datos (utilizando la capa de datos de la biblioteca empresarial)?

Por ejemplo, si agrego un nuevo valor de búsqueda en la base de datos, no quiero tener que agregar la declaración de valor enum estático adicional en el código.

¿Hay algo así? No quiero crear una enumeración estática generada por código (según el artículo de The Code Project Enum Code Generator - Generar código enum automáticamente a partir de tablas de búsqueda de bases de datos ) y preferiría que fuera completamente dinámica.


¿No estamos llegando a esto desde la dirección equivocada?

Si es probable que los datos cambien durante la vigencia de la versión implementada, una enumeración simplemente no es apropiada, y necesita usar un diccionario, hash u otra colección dinámica.

Si sabe que el conjunto de valores posibles se fija durante la vida de la versión desplegada, entonces es preferible una enumeración.

Si debe tener algo en su base de datos que replique el conjunto enumerado, ¿por qué no agregar un paso de implementación para borrar y volver a llenar la tabla de la base de datos con el conjunto definitivo de valores enum?


¿Te das cuenta de que los Enumeces deben especificarse en tiempo de compilación? No puede agregar dinámicamente enumeraciones durante el tiempo de ejecución, y ¿por qué lo haría, no habría ningún uso / referencia a ellas en el código?

De Professional C # 2008:

El poder real de las enumeraciones en C # es que detrás de las escenas se ejemplifican como estructuras derivadas de la clase base, System.Enum. Esto significa que es posible invocar métodos contra ellos para realizar algunas tareas útiles. Tenga en cuenta que, debido a la forma en que se implementa .NET Framework, no hay pérdida de rendimiento asociada con el tratamiento de las enumeraciones sintácticamente como estructuras. En la práctica, una vez que se compila su código, las enumeraciones existirán como tipos primitivos, como int y float.

Por lo tanto, no estoy seguro de que pueda usar Enums de la forma que desee.


¿Tiene que ser una enumeración real? ¿Qué hay de usar un Dictionary<string,int> lugar?

por ejemplo

Dictionary<string, int> MyEnum = new Dictionary(){{"One", 1}, {"Two", 2}}; Console.WriteLine(MyEnum["One"]);


Digamos que tienes lo siguiente en tu DB:

table enums ----------------- | id | name | ----------------- | 0 | MyEnum | | 1 | YourEnum | ----------------- table enum_values ---------------------------------- | id | enums_id | value | key | ---------------------------------- | 0 | 0 | 0 | Apple | | 1 | 0 | 1 | Banana | | 2 | 0 | 2 | Pear | | 3 | 0 | 3 | Cherry | | 4 | 1 | 0 | Red | | 5 | 1 | 1 | Green | | 6 | 1 | 2 | Yellow | ----------------------------------

Construya una selección para obtener los valores que necesita:

select * from enums e inner join enum_values ev on ev.enums_id=e.id where e.id=0

Construya el código fuente para la enumeración y obtendrá algo como:

String enumSourceCode = "enum " + enumName + "{" + enumKey1 + "=" enumValue1 + "," + enumKey2 + ... + "}";

(Obviamente esto está construido en un bucle de algún tipo).

Luego viene la parte divertida, compilando tu enumeración y usándola:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters cs = new CompilerParameters(); cp.GenerateInMemory = True; CompilerResult result = provider.CompileAssemblyFromSource(cp, enumSourceCode); Type enumType = result.CompiledAssembly.GetType(enumName);

Ahora tiene el tipo compilado y listo para usar.
Para obtener un valor enum almacenado en el DB, puede usar:

[Enum].Parse(enumType, value);

donde value puede ser el valor entero (0, 1, etc.) o el texto enum / key (Apple, Banana, etc.)


Estoy haciendo esto exactamente, pero necesitas hacer algún tipo de generación de código para que esto funcione.

En mi solución, agregué un proyecto "EnumeratedTypes". Esta es una aplicación de consola que obtiene todos los valores de la base de datos y construye las enumeraciones a partir de ellos. Luego guarda todas las enumeraciones en un ensamblaje.

El código de generación enum es así:

// Get the current application domain for the current thread AppDomain currentDomain = AppDomain.CurrentDomain; // Create a dynamic assembly in the current application domain, // and allow it to be executed and saved to disk. AssemblyName name = new AssemblyName("MyEnums"); AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); // Define a dynamic module in "MyEnums" assembly. // For a single-module assembly, the module has the same name as the assembly. ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, name.Name + ".dll"); // Define a public enumeration with the name "MyEnum" and an underlying type of Integer. EnumBuilder myEnum = moduleBuilder.DefineEnum("EnumeratedTypes.MyEnum", TypeAttributes.Public, typeof(int)); // Get data from database MyDataAdapter someAdapter = new MyDataAdapter(); MyDataSet.MyDataTable myData = myDataAdapter.GetMyData(); foreach (MyDataSet.MyDataRow row in myData.Rows) { myEnum.DefineLiteral(row.Name, row.Key); } // Create the enum myEnum.CreateType(); // Finally, save the assembly assemblyBuilder.Save(name.Name + ".dll");

Mis otros proyectos en la solución hacen referencia a este ensamblaje generado. Como resultado, puedo usar las enumeraciones dinámicas en código, completo con intellisense.

Luego, agregué un evento posterior a la compilación para que, una vez creado este proyecto "EnumeratedTypes", se ejecute a sí mismo y genere el archivo "MyEnums.dll".

Por cierto, ayuda a cambiar el orden de compilación de su proyecto para que "EnumeratedTypes" se construya primero. De lo contrario, una vez que comience a usar su .dll generado dinámicamente, no podrá hacer una compilación si el .dll alguna vez se elimina. (Tipo de problema del huevo y la gallina: sus otros proyectos en la solución necesitan este .dll para compilar correctamente, y no puede crear el .dll hasta que construya su solución ...)

Obtuve la mayor parte del código anterior de este artículo msdn .

¡Espero que esto ayude!


He hecho esto con una plantilla T4 . Es bastante trivial dejar caer un archivo .tt en su proyecto y configurar Visual Studio para ejecutar la plantilla T4 como un paso previo a la compilación.

El T4 genera un archivo .cs, lo que significa que puede hacer que solo consulte la base de datos y cree una enumeración en un archivo .cs a partir del resultado. Conectado como una tarea previa a la compilación, volvería a crear su enumeración en cada compilación, o puede ejecutar la T4 manualmente según sea necesario.


No creo que haya una buena forma de hacer lo que quieres. Y si lo piensas, no creo que esto sea lo que realmente quieres.

Si tuviera una enumeración dinámica, también significa que debe alimentarla con un valor dinámico cuando la referencia. Tal vez con mucha magia podría lograr algún tipo de IntelliSense que se encargaría de esto y generaría una enumeración para usted en un archivo DLL. Pero considere la cantidad de trabajo que tomaría, lo poco efectivo que sería acceder a la base de datos para obtener información de IntelliSense, así como la pesadilla de la versión que controla el archivo DLL generado.

Si realmente no desea agregar manualmente los valores enum (tendrá que agregarlos a la base de datos de todos modos) utilice una herramienta de generación de código en su lugar, por ejemplo, plantillas T4 . Haga clic derecho + ejecutar y obtendrá su enumeración estáticamente definida en el código y obtendrá todos los beneficios del uso de enumeraciones.



Siempre me gusta escribir mi propia "enumeración personalizada". Tengo una clase que es un poco más compleja, pero puedo reutilizarla:

public abstract class CustomEnum { private readonly string _name; private readonly object _id; protected CustomEnum( string name, object id ) { _name = name; _id = id; } public string Name { get { return _name; } } public object Id { get { return _id; } } public override string ToString() { return _name; } } public abstract class CustomEnum<TEnumType, TIdType> : CustomEnum where TEnumType : CustomEnum<TEnumType, TIdType> { protected CustomEnum( string name, TIdType id ) : base( name, id ) { } public new TIdType Id { get { return (TIdType)base.Id; } } public static TEnumType FromName( string name ) { try { return FromDelegate( entry => entry.Name.Equals( name ) ); } catch (ArgumentException ae) { throw new ArgumentException( "Illegal name for custom enum ''" + typeof( TEnumType ).Name + "''", ae ); } } public static TEnumType FromId( TIdType id ) { try { return FromDelegate( entry => entry.Id.Equals( id ) ); } catch (ArgumentException ae) { throw new ArgumentException( "Illegal id for custom enum ''" + typeof( TEnumType ).Name + "''", ae ); } } public static IEnumerable<TEnumType> GetAll() { var elements = new Collection<TEnumType>(); var infoArray = typeof( TEnumType ).GetFields( BindingFlags.Public | BindingFlags.Static ); foreach (var info in infoArray) { var type = info.GetValue( null ) as TEnumType; elements.Add( type ); } return elements; } protected static TEnumType FromDelegate( Predicate<TEnumType> predicate ) { if(predicate == null) throw new ArgumentNullException( "predicate" ); foreach (var entry in GetAll()) { if (predicate( entry )) return entry; } throw new ArgumentException( "Element not found while using predicate" ); } }

Ahora solo necesito crear mi enumeración que quiero usar:

public sealed class SampleEnum : CustomEnum<SampleEnum, int> { public static readonly SampleEnum Element1 = new SampleEnum( "Element1", 1, "foo" ); public static readonly SampleEnum Element2 = new SampleEnum( "Element2", 2, "bar" ); private SampleEnum( string name, int id, string additionalText ) : base( name, id ) { AdditionalText = additionalText; } public string AdditionalText { get; private set; } }

Por fin puedo usarlo como quiero:

static void Main( string[] args ) { foreach (var element in SampleEnum.GetAll()) { Console.WriteLine( "{0}: {1}", element, element.AdditionalText ); Console.WriteLine( "Is ''Element2'': {0}", element == SampleEnum.Element2 ); Console.WriteLine(); } Console.ReadKey(); }

Y mi resultado sería:

Element1: foo Is ''Element2'': False Element2: bar Is ''Element2'': True


Simplemente mostrando la answer de Pandincus con el código "de la estantería" y alguna explicación: necesita dos soluciones para este ejemplo (sé que también se puede hacer a través de una;), deje que los estudiantes avanzados lo presenten ...

Así que aquí está el DDL SQL para la tabla:

USE [ocms_dev] GO CREATE TABLE [dbo].[Role]( [RoleId] [int] IDENTITY(1,1) NOT NULL, [RoleName] [varchar](50) NULL ) ON [PRIMARY]

Así que aquí está el programa de la consola produciendo el dll:

using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Data.Common; using System.Data; using System.Data.SqlClient; namespace DynamicEnums { class EnumCreator { // after running for first time rename this method to Main1 static void Main () { string strAssemblyName = "MyEnums"; bool flagFileExists = System.IO.File.Exists ( AppDomain.CurrentDomain.SetupInformation.ApplicationBase + strAssemblyName + ".dll" ); // Get the current application domain for the current thread AppDomain currentDomain = AppDomain.CurrentDomain; // Create a dynamic assembly in the current application domain, // and allow it to be executed and saved to disk. AssemblyName name = new AssemblyName ( strAssemblyName ); AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly ( name, AssemblyBuilderAccess.RunAndSave ); // Define a dynamic module in "MyEnums" assembly. // For a single-module assembly, the module has the same name as // the assembly. ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule ( name.Name, name.Name + ".dll" ); // Define a public enumeration with the name "MyEnum" and // an underlying type of Integer. EnumBuilder myEnum = moduleBuilder.DefineEnum ( "EnumeratedTypes.MyEnum", TypeAttributes.Public, typeof ( int ) ); #region GetTheDataFromTheDatabase DataTable tableData = new DataTable ( "enumSourceDataTable" ); string connectionString = "Integrated Security=SSPI;Persist " + "Security Info=False;Initial Catalog=ocms_dev;Data " + "Source=ysg"; using (SqlConnection connection = new SqlConnection ( connectionString )) { SqlCommand command = connection.CreateCommand (); command.CommandText = string.Format ( "SELECT [RoleId], " + "[RoleName] FROM [ocms_dev].[dbo].[Role]" ); Console.WriteLine ( "command.CommandText is " + command.CommandText ); connection.Open (); tableData.Load ( command.ExecuteReader ( CommandBehavior.CloseConnection ) ); } //eof using foreach (DataRow dr in tableData.Rows) { myEnum.DefineLiteral ( dr[1].ToString (), Convert.ToInt32 ( dr[0].ToString () ) ); } #endregion GetTheDataFromTheDatabase // Create the enum myEnum.CreateType (); // Finally, save the assembly assemblyBuilder.Save ( name.Name + ".dll" ); } //eof Main } //eof Program } //eof namespace

Aquí está la programación de la consola imprimiendo la salida (recuerde que debe hacer referencia a la dll). Deje que los estudiantes avanzados presenten la solución para combinar todo en una sola solución con carga dinámica y verificar si ya hay build dll.

// add the reference to the newly generated dll use MyEnums ; class Program { static void Main () { Array values = Enum.GetValues ( typeof ( EnumeratedTypes.MyEnum ) ); foreach (EnumeratedTypes.MyEnum val in values) { Console.WriteLine ( String.Format ( "{0}: {1}", Enum.GetName ( typeof ( EnumeratedTypes.MyEnum ), val ), val ) ); } Console.WriteLine ( "Hit enter to exit " ); Console.ReadLine (); } //eof Main } //eof Program


Una forma de mantener las entradas y crear una lista dinámica de valores al mismo tiempo es usar las entradas que tiene actualmente con un diccionario creado dinámicamente.

Dado que la mayoría de los Enums se utilizan en el contexto en que se definen para ser utilizados, y las "enum dinámicas" serán soportadas por procesos dinámicos, puede distinguir el 2.

El primer paso es crear una tabla / colección que contenga los ID y las referencias para las entradas dinámicas. En la tabla, se autoincrementará mucho más que su valor más grande de Enum.

Ahora viene la parte para sus Enum dinámicos, supongo que usará los Enums para crear un conjunto de condiciones que apliquen un conjunto de reglas, algunas se generan dinámicamente.

Get integer from database If Integer is in Enum -> create Enum -> then run Enum parts If Integer is not a Enum -> create Dictionary from Table -> then run Dictionary parts.


Usar enums dinámicos es malo sin importar en qué dirección. Tendrá que pasar por el problema de "duplicar" los datos para garantizar un código claro y fácil de mantener en el futuro.

Si comienza a introducir bibliotecas generadas automáticamente, seguramente causará más confusión a los futuros desarrolladores que tengan que actualizar su código que simplemente hacer que su enumeración esté codificada dentro del objeto de clase apropiado.

Los otros ejemplos sonarán agradables y emocionantes, pero piense en la sobrecarga en el mantenimiento del código en comparación con lo que obtiene de él. Además, ¿esos valores van a cambiar con tanta frecuencia?


Desea System.Web.Compilation.BuildProvider

También dudo de la sabiduría de hacer esto, pero quizás haya un buen caso de uso en el que no puedo pensar.

Lo que está buscando son Proveedores de compilación, es decir, System.Web.Compilation.BuildProvider

SubSonic utiliza muy eficazmente, puedes descargar la fuente y ver cómo los usan, no necesitarás la mitad de intrincada que lo que están haciendo.

Espero que esto ayude.