132 votes

Enum dynamique en c#

Comment puis-je créer une dynamique enum (et par la suite utiliser l'enum choix) en C# basés sur des valeurs dans une base de données de la table de recherche (en utilisant entreprise de la bibliothèque de la couche de données)?

Par exemple, Si j'ajoute une nouvelle valeur de recherche dans la base de données, je ne veux pas avoir à ajouter de la statique enum déclaration de la valeur dans le code.

Est-il une telle chose comme cela? Je ne veux pas créer un code généré statique enum (selon Le Projet de Code de l'article Enum Générateur de Code Générant enum code automatiquement à partir de la base de données les tables) et préférerait qu'il soit complètement dynamique.

104voto

Pandincus Points 5785

Je suis en train de faire cette chose exacte, mais vous avez besoin de faire une sorte de génération de code pour que cela fonctionne.

Dans ma solution, j'ai ajouté un projet "EnumeratedTypes". C'est une application console qui récupère toutes les valeurs de la base de données et construit les énumérations d'eux. Puis il enregistre toutes les énumérations à une assemblée.

L'enum de génération de code comme ceci:

// 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");

Mes autres projets dans la solution de référence ce assembleur généré. En conséquence, je peux alors utiliser la dynamique des énumérations dans le code, complet avec intellisense.

Ensuite, j'ai ajouté un post-événement de construction, de sorte qu'après cette "EnumeratedTypes" le projet est construit, il va lui-même et génère le "MyEnums.dll" fichier.

Par ailleurs, il permet de changer l' ordre de construction de votre projet, afin que "EnumeratedTypes" est construit en premier. Sinon, une fois que vous commencez à utiliser votre générés dynamiquement .dll, vous ne serez pas en mesure de faire un build si l' .dll n'est jamais supprimé. (L'oeuf et la poule genre de problème, vos autres projets de la solution .dll pour construire correctement, et vous ne pouvez pas créer les .dll jusqu'à ce que vous construisez votre solution...)

J'ai obtenu la plupart de code ci-dessus à partir de cet article msdn.

Espérons que cette aide!

55voto

Marcus L Points 2309

Vous vous rendez compte que les Énumérations doit être spécifié au moment de la compilation? Vous ne pouvez pas ajouter dynamiquement des enums au cours de l'exécution - et pourquoi voudriez-vous, il n'y aurait pas d'utilisation/une référence dans le code?

Des Professionnels Du C# 2008:

La véritable puissance de l'enum en C#, c'est que derrière les scènes qu'ils sont instanciés comme des structures dérivées de la classe de base du Système.Enum . Cela signifie qu'il est possible d'appeler des méthodes sur eux pour effectuer certaines tâches utiles. A noter qu'en raison de la façon dont l' .NET Framework est mis en œuvre il n'y a aucune perte de performance associés au traitement de la enums syntaxiquement comme des structures. Dans la pratique, une fois que votre code est compilé, les énumérations existera tant que les types primitifs, tout comme int et float .

Donc, je ne suis pas sûr que vous pouvez utiliser les Énumérations la façon dont vous voulez.

23voto

Sandeep Datta Points 7344

Doit-il être un enum réel ? Qu’en est-il en utilisant un `` à la place ?

par exemple

13voto

Sani Huttunen Points 10433

Disons que vous avez dans votre base de données:

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

La construction d'un select pour récupérer les valeurs dont vous avez besoin:

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

Construire le code source pour l'enum et vous obtiendrez quelque chose comme:

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

(évidemment, ce n'est construit dans une boucle d'une certaine sorte.)

Puis vient la partie la plus amusante, la Compilation de votre enum et de l'utiliser:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cs = new CompilerParameters();
cp.GenerateInMemory = True;

CompilerResult result = provider.CompileAssemblyFromSource(cp, enumSourceCode);

Type enumType = result.CompiledAssembly.GetType(enumName);

Maintenant, vous avez le type compilé et prêt à l'emploi.
Pour obtenir une valeur d'enum stockées dans la base de données, vous pouvez utiliser:

[Enum].Parse(enumType, value);

où valeur peut être soit la valeur de l'entier (0, 1, etc.) ou enum texte/touche (Pomme, Banane, etc.)

10voto

YordanGeorgiev Points 1222

Il suffit de montrer la réponse de Pandincus avec "le plateau" de code et quelques explications: Vous avez besoin de deux solutions pour cet exemple ( je sais que ça pourrait être fait via un aussi ; ), laissez les étudiants les plus avancés de la présenter ...

Voici donc le DDL SQL de la table :

USE [ocms_dev]
    GO

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

Voici donc le programme de la console la production de la 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 

Ici est la Console de programmation de l'impression de la sortie ( rappelez-vous qu'il a à faire référence à la dll ). Laissez l'avance aux élèves de présenter la solution pour combiner le tout dans une solution avec le chargement dynamique et vérifier s'il y est déjà construire 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X