Monday, July 1, 2013

Generate class and properties at runtime

To generate a class and properties at run-time.

using System;
using System.Data;
using System.Reflection;
using System.Collections.Generic;

namespace ReportEngine
{
    class Program
    {
        static void Main(string[] args)
        {

            DataTable table = InputGeneration.GetTable();

            //InputGeneration.DisplayTable(table);


            #region "Method2 - Generate class and properties alone at runtime"

            Console.WriteLine("\n---Method2 - Generate class and properties alone at runtime--------------\n");

            IEnumerableDynamicProperty> properties = Method2.GenerateProperties(table);

            Type type = Method2.GenerateClass(properties);

            //The below combination will return all non-public instance properties on the type.
            var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

            PropertyInfo[] props = type.GetProperties(flags);
            for (int i = 0; i < props.Length; i++)
            {
                Console.Write("\t{0}\t", props[i].Name);
            }
            Console.WriteLine("\t");

            Method2 m2 = new Method2();
            m2.AssignClassValues(type, table);


            #endregion

            Console.WriteLine("\n---------------------------------------------------------\n");

            Console.ReadLine();
        }
    }
}

InputGeneration:

using System;
using System.Data;

namespace ReportEngine
{
    public static class InputGeneration
    {
        public static DataTable GetTable()
        {
            //
            // Here we create a DataTable with four columns.
            //
            DataTable table = new DataTable();
            table.Columns.Add("Dosage", typeof(int));
            table.Columns.Add("Drug", typeof(string));
            table.Columns.Add("Patient", typeof(string));
            table.Columns.Add("Date", typeof(DateTime));

            //
            // Here we add five DataRows.
            //
            table.Rows.Add(25, "Indocin", "David", DateTime.Now);
            table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
            table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
            table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
            table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
            return table;
        }

        public static void DisplayTable(DataTable dt)
        {
            if (dt.Rows.Count > 0)
            {
                foreach (DataColumn column in dt.Columns)
                {
                    Console.Write("\t{0}\t", column.ColumnName);
                }
                Console.WriteLine("\t");
                foreach (DataRow row in dt.Rows)
                {
                    foreach (DataColumn column in dt.Columns)
                        Console.Write("\t{0}\t", row[column]);

                    Console.WriteLine("\t");
                }
            }
            else
                Console.WriteLine("No Current Rows Found");
        }
    }
}

Method2:

using System;
using System.Data;
using System.Collections.Generic;
using ReportEngine.ClassAtRuntime;
using System.Reflection;

namespace ReportEngine
{
    public class Method2
    {
        public static IEnumerable<DynamicProperty> GenerateProperties(DataTable table)
        {
            List<DynamicProperty> Properties = new List<DynamicProperty>();
            foreach (DataColumn column in table.Columns)
            {
                Properties.Add(new DynamicProperty(column.ColumnName.ToUpper(), column.DataType));
            }

            return Properties;
        }

        public static Type GenerateClass(IEnumerable<DynamicProperty> properties)
        {
            Type type = Dynamic.CreateClass(properties);
            return type;
        }

        public void AssignClassValues(Type type, DataTable table)
        {
            List<object> lstobj = new List<object>();

            foreach (DataRow dr in table.Rows)
            {
                var obj = Activator.CreateInstance(type);
                PropertyInfo[] props = obj.GetType().GetProperties();
                for (int i = 0; i < props.Length; i++)
                {
                    if (props[i].CanWrite)
                    {
                        try
                        {
                            if (dr[props[i].Name] != null && !dr.IsNull(props[i].Name))
                            {
                                props[i].SetValue(obj, dr[props[i].Name], null);
                            }
                            else
                            {
                                props[i].SetValue(props[i].Name, null, null);
                            }
                        }
                        catch // DB COLUMN does not exist for this property.
                        {
                            props[i].SetValue(props[i].Name, null, null);
                        }
                    }
                }
                lstobj.Add(obj);
            }
        }

        public void ReadClassValues(List<object> lstobj)
        {
            foreach (object obj in lstobj)
            {
               
            }
        }

        public void getModelFromObject(Type type, DataTable table)
        {
            List el = new List();
            foreach (DataRow dr in table.Rows)
            {
                T item = (T)Activator.CreateInstance(type);
                getObject(dr, ref item, table);
                T tsts = item;

                ((List)el).Add(item);

            }
        }

        public void getObject(DataRow dr, ref T obj, DataTable dt)
        {

            foreach (DataColumn dc in dt.Columns)
            {
                if (obj.GetType().GetProperty(dc.ColumnName) != null)
                {
                    obj.GetType().GetProperty(dc.ColumnName).SetValue(obj, dr[dc.ColumnName], null);
                }
            }
        }

    }
}



DynamicClasswithProperties:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ReportEngine.ClassAtRuntime
{

    class DynamicClasswithProperties
    {
    }

    public abstract class DynamicClass
    {
        public override string ToString()
        {
            PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            for (int i = 0; i < props.Length; i++)
            {
                if (i > 0) sb.Append(", ");
                sb.Append(props[i].Name);
                sb.Append("=");
                sb.Append(props[i].GetValue(this, null));
            }
            sb.Append("}");
            return sb.ToString();
        }
    }

    public class DynamicProperty
    {
        string name;
        Type type;

        public DynamicProperty(string name, Type type)
        {
            if (name == null) throw new ArgumentNullException("name");
            if (type == null) throw new ArgumentNullException("type");
            this.name = name;
            this.type = type;
        }

        public string Name
        {
            get { return name; }
        }

        public Type Type
        {
            get { return type; }
        }
    }

    public static class Dynamic
    {
        public static Type CreateClass(IEnumerable<DynamicProperty> properties)
        {
            return ClassFactory.Instance.GetDynamicClass(properties);
        }
    }
    internal class Signature : IEquatable<Signature>
    {
        public DynamicProperty[] properties;
        public int hashCode;

        public Signature(IEnumerable<DynamicProperty> properties)
        {
            this.properties = properties.ToArray();
            hashCode = 0;
            foreach (DynamicProperty p in properties)
            {
                hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
            }
        }

        public override int GetHashCode()
        {
            return hashCode;
        }

        public override bool Equals(object obj)
        {
            return obj is Signature ? Equals((Signature)obj) : false;
        }

        public bool Equals(Signature other)
        {
            if (properties.Length != other.properties.Length) return false;
            for (int i = 0; i < properties.Length; i++)
            {
                if (properties[i].Name != other.properties[i].Name ||
                    properties[i].Type != other.properties[i].Type) return false;
            }
            return true;
        }
    }

    internal class ClassFactory
    {
        public static readonly ClassFactory Instance = new ClassFactory();

        static ClassFactory() { }  // Trigger lazy initialization of static fields

        ModuleBuilder module;
        Dictionary<Signature, Type> classes;
        int classCount;
        ReaderWriterLock rwLock;

        private ClassFactory()
        {
            AssemblyName name = new AssemblyName("DynamicClasses");
            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
            #if ENABLE_LINQ_PARTIAL_TRUST
            new ReflectionPermission(PermissionState.Unrestricted).Assert();
            #endif
            try
            {
                module = assembly.DefineDynamicModule("Module");
            }
            finally
            {
            #if ENABLE_LINQ_PARTIAL_TRUST
                PermissionSet.RevertAssert();
            #endif
            }
            classes = new Dictionary<Signature, Type>();
            rwLock = new ReaderWriterLock();
        }

        public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
        {
            rwLock.AcquireReaderLock(Timeout.Infinite);
            try
            {
                Signature signature = new Signature(properties);
                Type type;
                if (!classes.TryGetValue(signature, out type))
                {
                    type = CreateDynamicClass(signature.properties);
                    classes.Add(signature, type);
                }
                return type;
            }
            finally
            {
                rwLock.ReleaseReaderLock();
            }
        }

        Type CreateDynamicClass(DynamicProperty[] properties)
        {
            LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
            try
            {
                string typeName = "DynamicClass" + (classCount + 1);
                #if ENABLE_LINQ_PARTIAL_TRUST
                new ReflectionPermission(PermissionState.Unrestricted).Assert();
                #endif
                try
                {
                    TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
                        TypeAttributes.Public, typeof(DynamicClass));
                    FieldInfo[] fields = GenerateProperties(tb, properties);
                    GenerateEquals(tb, fields);
                    GenerateGetHashCode(tb, fields);
                    Type result = tb.CreateType();
                    classCount++;
                    return result;
                }
                finally
                {
                    #if ENABLE_LINQ_PARTIAL_TRUST
                    PermissionSet.RevertAssert();
                    #endif
                }
            }
            finally
            {
                rwLock.DowngradeFromWriterLock(ref cookie);
            }
        }

        FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
        {
            FieldInfo[] fields = new FieldBuilder[properties.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                DynamicProperty dp = properties[i];
                FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);
                PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
                MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,
                    MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                    dp.Type, Type.EmptyTypes);
                ILGenerator genGet = mbGet.GetILGenerator();
                genGet.Emit(OpCodes.Ldarg_0);
                genGet.Emit(OpCodes.Ldfld, fb);
                genGet.Emit(OpCodes.Ret);
                MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,
                    MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                    null, new Type[] { dp.Type });
                ILGenerator genSet = mbSet.GetILGenerator();
                genSet.Emit(OpCodes.Ldarg_0);
                genSet.Emit(OpCodes.Ldarg_1);
                genSet.Emit(OpCodes.Stfld, fb);
                genSet.Emit(OpCodes.Ret);
                pb.SetGetMethod(mbGet);
                pb.SetSetMethod(mbSet);
                fields[i] = fb;
            }
            return fields;
        }

        void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)
        {
            MethodBuilder mb = tb.DefineMethod("Equals",
                MethodAttributes.Public | MethodAttributes.ReuseSlot |
                MethodAttributes.Virtual | MethodAttributes.HideBySig,
                typeof(bool), new Type[] { typeof(object) });
            ILGenerator gen = mb.GetILGenerator();
            LocalBuilder other = gen.DeclareLocal(tb);
            Label next = gen.DefineLabel();
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Isinst, tb);
            gen.Emit(OpCodes.Stloc, other);
            gen.Emit(OpCodes.Ldloc, other);
            gen.Emit(OpCodes.Brtrue_S, next);
            gen.Emit(OpCodes.Ldc_I4_0);
            gen.Emit(OpCodes.Ret);
            gen.MarkLabel(next);
            foreach (FieldInfo field in fields)
            {
                Type ft = field.FieldType;
                Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
                next = gen.DefineLabel();
                gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, field);
                gen.Emit(OpCodes.Ldloc, other);
                gen.Emit(OpCodes.Ldfld, field);
                gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
                gen.Emit(OpCodes.Brtrue_S, next);
                gen.Emit(OpCodes.Ldc_I4_0);
                gen.Emit(OpCodes.Ret);
                gen.MarkLabel(next);
            }
            gen.Emit(OpCodes.Ldc_I4_1);
            gen.Emit(OpCodes.Ret);
        }

        void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
        {
            MethodBuilder mb = tb.DefineMethod("GetHashCode",
                MethodAttributes.Public | MethodAttributes.ReuseSlot |
                MethodAttributes.Virtual | MethodAttributes.HideBySig,
                typeof(int), Type.EmptyTypes);
            ILGenerator gen = mb.GetILGenerator();
            gen.Emit(OpCodes.Ldc_I4_0);
            foreach (FieldInfo field in fields)
            {
                Type ft = field.FieldType;
                Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
                gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, field);
                gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
                gen.Emit(OpCodes.Xor);
            }
            gen.Emit(OpCodes.Ret);
        }
    }
}

No comments: