Créer automatiquement un Enum basé sur des valeurs dans une table de recherche de firebase database?

Comment créer automatiquement une énumération et utiliser ensuite ses valeurs en C # en fonction des valeurs d’une table de recherche de firebase database (à l’aide de la couche de données de la bibliothèque d’entreprise)?

Par exemple, si j’ajoute une nouvelle valeur de recherche dans la firebase database, je ne veux pas avoir à append manuellement la déclaration de valeur d’énumération statique supplémentaire dans le code – je souhaite que l’énumération rest synchronisée avec la firebase database.

Y a-t-il une telle chose?


Je ne veux pas créer un enum statique généré par le code (conformément à l’article de Code Project Enum Code Generator – Génération automatique du code enum à partir des tables de consultation de firebase database ) et préférerais qu’il soit complètement automatique.

Je fais cette chose exacte, mais vous devez faire une sorte de génération de code pour que cela fonctionne.

Dans ma solution, j’ai ajouté un projet “EnumeratedTypes”. Ceci est une application console qui récupère toutes les valeurs de la firebase database et construit les énumérations à partir de celles-ci. Ensuite, il enregistre toutes les énumérations à un assemblage.

Le code de génération enum est 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", TypeAtsortingbutes.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 font référence à cet assemblage généré. En conséquence, je peux alors utiliser les énumérations dynamics dans le code, complet avec intellisense.

Ensuite, j’ai ajouté un événement de post-construction afin qu’après l’exécution de ce projet “EnumeratedTypes”, il s’exécute et génère le fichier “MyEnums.dll”.

En passant, il est utile de modifier l’ ordre de construction de votre projet pour que “EnumeratedTypes” soit créé en premier. Sinon, une fois que vous commencerez à utiliser votre fichier .dll généré dynamicment, vous ne pourrez plus faire de compilation si le fichier .dll est supprimé. (Le type de problème lié au poulet et aux œufs – vos autres projets dans la solution ont besoin de ce fichier .dll pour se construire correctement, et vous ne pouvez pas créer le fichier .dll tant que vous n’avez pas construit votre solution …)

J’ai reçu la plupart du code ci-dessus de cet article msdn .

J’espère que cela t’aides!

Les énumérations doivent être spécifiées au moment de la compilation, vous ne pouvez pas append dynamicment des énumérations au moment de l’exécution – et pourquoi ne les utiliseriez-vous pas dans le code?

De Professional C # 2008:

Le véritable pouvoir des énumérations en C # est que, dans les coulisses, elles sont instanciées en tant que structures dérivées de la classe de base, System.Enum. Cela signifie qu’il est possible d’appeler des méthodes contre eux pour effectuer des tâches utiles. Notez qu’en raison de la manière dont .NET Framework est implémenté, il n’y a pas de perte de performances associée au traitement syntaxique des énumérations en tant que structures. En pratique, une fois votre code compilé, les énumérations existeront en tant que types primitifs, tout comme int et float.

Donc, je ne suis pas sûr que vous puissiez utiliser Enums comme vous le souhaitez.

Est-ce que ça doit être un enum réel? Que diriez-vous d’utiliser un Dictionary place?

par exemple

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

Disons que vous avez les éléments suivants dans votre firebase database:

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

Construisez une sélection pour obtenir 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 

Construisez le code source de l’énumération et vous obtiendrez quelque chose comme:

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

(évidemment, ceci est construit dans une boucle quelconque)

Puis vient la partie amusante Comstackr votre enum et l’utiliser:

 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); ComstackrParameters cs = new ComstackrParameters(); cp.GenerateInMemory = True; ComstackrResult result = provider.ComstackAssemblyFromSource(cp, enumSourceCode); Type enumType = result.ComstackdAssembly.GetType(enumName); 

Vous avez maintenant le type compilé et prêt à l’emploi.
Pour obtenir une valeur enum stockée dans la firebase database, vous pouvez utiliser:

 [Enum].Parse(enumType, value); 

où value peut être soit la valeur entière (0, 1, etc.), soit le texte / clé enum (Apple, Banana, etc.)

Il suffit de montrer la réponse de Pandincus avec le code “of the shelf” et quelques explications: vous avez besoin de deux solutions pour cet exemple (je sais que cela pourrait se faire via un autre;), laissez les étudiants avancés le présenter …

Voici donc le SQL DDL pour 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 qui produit 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 () { ssortingng 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", TypeAtsortingbutes.Public, typeof ( int ) ); #region GetTheDataFromTheDatabase DataTable tableData = new DataTable ( "enumSourceDataTable" ); ssortingng connectionSsortingng = "Integrated Security=SSPI;Persist " + "Security Info=False;Initial Catalog=ocms_dev;Data " + "Source=ysg"; using (SqlConnection connection = new SqlConnection ( connectionSsortingng )) { SqlCommand command = connection.CreateCommand (); command.CommandText = ssortingng.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].ToSsortingng (), Convert.ToInt32 ( dr[0].ToSsortingng () ) ); } #endregion GetTheDataFromTheDatabase // Create the enum myEnum.CreateType (); // Finally, save the assembly assemblyBuilder.Save ( name.Name + ".dll" ); } //eof Main } //eof Program } //eof namespace 

Voici la programmation de la console imprimant la sortie (rappelez-vous qu’elle doit faire référence à la DLL). Laissez les étudiants avancés présenter la solution pour combiner tout dans une solution avec un chargement dynamic et en vérifiant s’il existe déjà une DLL de compilation.

 // 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 ( Ssortingng.Format ( "{0}: {1}", Enum.GetName ( typeof ( EnumeratedTypes.MyEnum ), val ), val ) ); } Console.WriteLine ( "Hit enter to exit " ); Console.ReadLine (); } //eof Main } //eof Program 

Je l’ai fait avec un modèle T4 . Il est assez sortingvial de déposer un fichier .tt dans votre projet et de configurer Visual Studio pour qu’il exécute le modèle T4 comme une étape préalable à la création.

Le T4 génère un fichier .cs, ce qui signifie que vous pouvez simplement demander à la firebase database et créer une énumération dans un fichier .cs à partir du résultat. Câblé comme une tâche de pré-construction, il recréerait votre enum sur chaque version, ou vous pouvez exécuter le T4 manuellement à la place.

Vous voulez System.Web.Compilation.BuildProvider

Je doute aussi de la sagesse de le faire, mais il y a peut-être un cas d’utilisation auquel je ne peux pas penser.

Ce que vous recherchez, ce sont des fournisseurs de build, par exemple System.Web.Compilation.BuildProvider

Ils sont utilisés très efficacement par SubSonic , vous pouvez télécharger le source et voir comment ils les utilisent, vous n’aurez besoin de rien de moins complexe que ce qu’ils font.

J’espère que cela t’aides.

J’aime toujours écrire mon propre “enum personnalisé”. Je possède une classe un peu plus complexe, mais je peux la réutiliser:

 public abstract class CustomEnum { private readonly ssortingng _name; private readonly object _id; protected CustomEnum( ssortingng name, object id ) { _name = name; _id = id; } public ssortingng Name { get { return _name; } } public object Id { get { return _id; } } public override ssortingng ToSsortingng() { return _name; } } public abstract class CustomEnum : CustomEnum where TEnumType : CustomEnum { protected CustomEnum( ssortingng name, TIdType id ) : base( name, id ) { } public new TIdType Id { get { return (TIdType)base.Id; } } public static TEnumType FromName( ssortingng 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 GetAll() { var elements = new Collection(); 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 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" ); } } 

Maintenant, je dois juste créer mon enum que je veux utiliser:

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

Enfin je peux l’utiliser comme je veux:

  static void Main( ssortingng[] 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(); } 

Et ma sortie serait:

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

Ne venons-nous pas à cela du mauvais côté?

Si les données sont susceptibles de changer pendant la durée de vie de la version déployée, une énumération n’est tout simplement pas appropriée et vous devez utiliser un dictionnaire, un hachage ou une autre collection dynamic.

Si vous savez que l’ensemble des valeurs possibles est fixe pour la durée de vie de la version déployée, un enum est préférable.

Si vous devez avoir quelque chose dans votre firebase database qui réplique l’ensemble énuméré, alors pourquoi ne pas append une étape de déploiement pour effacer et repeupler la table de firebase database avec l’ensemble définitif des valeurs d’énumération?

Vous pouvez utiliser CodeSmith pour générer quelque chose comme ceci:

http://www.csharping.com/PermaLink,guid,cef1b637-7d37-4691-8e49-138cbf1d51e9.aspx

Je ne pense pas qu’il y ait une bonne façon de faire ce que vous voulez. Et si vous y réfléchissez, je ne pense pas que ce soit ce que vous voulez vraiment.

Si vous avez un enum dynamic, cela signifie également que vous devez le nourrir avec une valeur dynamic lorsque vous le référencez. Peut-être qu’avec beaucoup de magie, vous pourriez réaliser une sorte d’ IntelliSense qui s’en chargerait et générerait un enum pour vous dans un fichier DLL. Mais considérez la quantité de travail qu’il faudrait, combien il serait inefficace d’accéder à la firebase database pour récupérer des informations sur IntelliSense ainsi que le cauchemar de la version contrôlant le fichier DLL généré.

Si vous ne voulez vraiment pas append manuellement les valeurs d’énumération (vous devrez de toute façon les append à la firebase database), utilisez plutôt un outil de génération de code, par exemple des modèles T4 . Clic droit + exécuter et vous avez votre énumement défini statiquement dans le code et vous obtenez tous les avantages de l’utilisation des énumérations.

Utiliser des énumérations dynamics est mauvais, quel que soit le chemin. Vous devrez faire le nécessaire pour “dupliquer” les données afin de garantir un code clair et simple, facile à gérer à l’avenir.

Si vous commencez à introduire des bibliothèques générées automatiquement, vous êtes certainement en train de créer plus de confusion pour les futurs développeurs qui doivent mettre à jour votre code plutôt que de simplement créer votre enum codé dans l’object de classe approprié.

Les autres exemples donnés sont sympas et passionnants, mais pensez à la surcharge de maintenance du code par rapport à ce que vous en obtenez. En outre, ces valeurs vont-elles changer fréquemment?

Une façon de conserver les énumérations et de créer une liste dynamic de valeurs en même temps consiste à utiliser les énumérations que vous avez actuellement avec un dictionnaire créé dynamicment.

Comme la plupart des Enums sont utilisés dans le contexte où ils sont définis et que les “énumérations dynamics” sont supscopes par des processus dynamics, vous pouvez distinguer les 2.

La première étape consiste à créer une table / collection contenant les ID et les références des entrées dynamics. Dans la table, vous allez auto-incrémenter beaucoup plus grande que votre plus grande valeur Enum.

Maintenant, la partie pour vos Enums dynamics, je suppose que vous utiliserez les Enums pour créer un ensemble de conditions qui appliquent un ensemble de règles, certaines sont générées dynamicment.

 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. 

classe constructeur

 public class XEnum { private EnumBuilder enumBuilder; private int index; private AssemblyBuilder _ab; private AssemblyName _name; public XEnum(ssortingng enumname) { AppDomain currentDomain = AppDomain.CurrentDomain; _name = new AssemblyName("MyAssembly"); _ab = currentDomain.DefineDynamicAssembly( _name, AssemblyBuilderAccess.RunAndSave); ModuleBuilder mb = _ab.DefineDynamicModule("MyModule"); enumBuilder = mb.DefineEnum(enumname, TypeAtsortingbutes.Public, typeof(int)); } ///  /// adding one ssortingng to enum ///  ///  ///  public FieldBuilder add(ssortingng s) { FieldBuilder f = enumBuilder.DefineLiteral(s, index); index++; return f; } ///  /// adding array to enum ///  ///  public void addRange(ssortingng[] s) { for (int i = 0; i < s.Length; i++) { enumBuilder.DefineLiteral(s[i], i); } } ///  /// getting index 0 ///  ///  public object getEnum() { Type finished = enumBuilder.CreateType(); _ab.Save(_name.Name + ".dll"); Object o1 = Enum.Parse(finished, "0"); return o1; } ///  /// getting with index ///  ///  ///  public object getEnum(int i) { Type finished = enumBuilder.CreateType(); _ab.Save(_name.Name + ".dll"); Object o1 = Enum.Parse(finished, i.ToSsortingng()); return o1; } } 

créer un object

 ssortingng[] types = { "Ssortingng", "Boolean", "Int32", "Enum", "Point", "Thickness", "long", "float" }; XEnum xe = new XEnum("Enum"); xe.addRange(types); return xe.getEnum();