<$BlogRSDUrl$>

Friday, December 12, 2003

last day in the office 

A long awaited holiday starts as soon as I leave the office today!!!
Getting away from the office would enable me to do some *serious* relaxation, but more importantly (possibly more exciting): I'll have more time for private venturing :) whatever the heck that might be...

I'm developing my first large-scale ASP.NET based site, which should be live in January if all goes well. I'm using mySQL on the backend, and I'm quite worried about that part of it. I've heard many doomsday prophecies about it, but then I say there's only one way to find out. (Testing does not yield any problems so far).

Yeehah. I'm outta here.

Monday, December 08, 2003

dynamic enums 

Like most people in the software industry, I have these (amongst a gazillion others) few simple requirements:

1)  I want developers' code to be as readable as possible. (!)
2)  I want to simplify the task of writing code as much as possible
     (In this case, by using intellisense)
3)  I like the idea of increased control over what's available to developers, as this increases the degree to which code adheres to an internal standard.

I came up with the far-fetched idea of having a table in a database where values can be set, specifying certain enums available to developers.

Let me provide a simple example:
Suppose a base class for users of an app (let's call this class 'User') has one public property called 'AuthorityLevel', which contains an integer-value to denote a user's level of authority. A user with level 3 will have access to admin-functions, whereas a user with level 2 will only be able to print certain reports, for instance. Don't look too much into this class - it's purpose is to merely serve as an example!

The following enum will provide you with what you need:

    public enum AuthorityLevel {Minion = 1, Worker, Manager}

Once it's hard-coded, however, there's no easy way of changing it. It would be nice to be able to change the values or descriptions in this enum, knowing that developers will write code against whatever you specified.
I thought of this solution last week: The enums you want your developers to use should reside in a seperate DLL, to be referenced at design-time. As soon as this DLL changes, new descriptions will be available and used in subsequent code.

Let's take our example. If I create a table in a database as follows:

table AuthorityLevel:
VAL DESCRIPTION
1 Minion
2 Worker
3 Manager

I can dynamically generate a DLL with the described enum. As soon as I change any of the DB-values, my DLL would need to be regenerated. It's easy to write a simple .exe (shown below) that gets called whenever any of these values change. This .exe will use Reflection.Emit to create and compile the DLL containing the needed enums.

The C# source for the .exe would look something like this:

using System;
using System.Collections;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;


namespace Ernst.Test
{
    public class EnumBuilder
    {
        static AssemblyBuilder myAssemblyBuilder;
        static ModuleBuilder myModuleBuilder;
        static EnumBuilder myEnumBuilder;

        public static void BuildEnum()
        {
            try
            {
                CreateEnums(Thread.GetDomain(), AssemblyBuilderAccess.Save);
                Type[] myTypeArray = myModuleBuilder.GetTypes();
                foreach(Type myType in myTypeArray)
                {
                    Console.WriteLine("Enum Builder defined in the module builder is: "
                        + myType.Name);
                }

                Console.WriteLine("Enum TypeToken is :"
                    + myEnumBuilder.TypeToken.ToString());
                Console.WriteLine("Enum UnderLyingField is :"
                    + myEnumBuilder.UnderlyingField.ToString());
                Console.WriteLine("Enum UnderLyingSystemType is :"
                    + myEnumBuilder.UnderlyingSystemType.ToString());
                Console.WriteLine("Enum GUID is :"
                    + myEnumBuilder.GUID.ToString());
                myAssemblyBuilder.Save("EmittedAssembly.dll");
            }
            catch(NotSupportedException ex)
            {
                Console.WriteLine("The following is the exception is raised: " + ex.Message);
            }
            catch(Exception e)
            {
                Console.WriteLine("The following is the exception raised: " + e.Message);
            }
        }

        private static void CreateEnums(AppDomain myAppDomain, AssemblyBuilderAccess access)
        {
            // Create a name for the assembly.
            AssemblyName myAssemblyName = new AssemblyName();
            myAssemblyName.Name = "DBEnums";
            // Create the dynamic assembly.
            myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName,
                AssemblyBuilderAccess.Save);
            // Create a dynamic module.
            myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("DBEnums",
                "DBEnums.mod");
            // Create a dynamic Enum.
            myEnumBuilder = myModuleBuilder.DefineEnum((string)GetNameSpace(),
                TypeAttributes.Public, typeof(Int32));

            string[] Fields = GetFields();
            int index = 1;
            foreach (string field in Fields)
            {
                FieldBuilder myFieldBuilder = myEnumBuilder.DefineLiteral(field, index++);
            }

            myEnumBuilder.CreateType();
        }

        private static string GetNameSpace()
        {
            //There's obviously a better way to name your enum,
            //for instance retrieving it from your DB
            return "Ernst.Test.DBEnums";
        }

        private string[] GetFields()
        {
            //Code to connect to DB and retrieve enum-values, return as string-array
        }
    }
}

Note that the code above assumes that your enum will be of type Int32. This is easy to change by hard-coding, or even by specifying a type in your database-values. You can even decide on a type based on the datatype of the SQL column.

I have tried to foresee compatibility issues regarding this process, and will keep you posted on my findings.

This page is powered by Blogger. Isn't yours?