Friday 16 December 2011

Create Dynamic Class and Properties by Reflection


This topic shows how to create a simple generic type with two type parameters, how to apply class constraints, special constraints to the type parameters, and how to create members that use the type parameters of the class as parameter types and return types.

The goal of the program to generate a dynamic assembly that houses a single module and a single type, and exposes a single method (which simply writes a line of text to the console), then save this assembly to disk as an executable file. (For a more useful example of Reflection.Emit in action) 


To define a generic type

Define a dynamic assembly named GenericEmitExample1. In this example, the assembly is executed and saved to disk, so AssemblyBuilderAccess.Run is specified.


AssemblyBuilder asmBuilder
{
    get;
    set;
}
ModuleBuilder modBuilder
{
    get;
    set;
}
AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("Generic.Data");
asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
// An assembly is made up of executable modules. For a single-

Define a dynamic module. An assembly is made up of executable modules. For a single-module assembly, the module name is the same as the assembly name, and the file name is the module name plus an extension.


// module assembly, the module name and file name are the same
// as the assembly name.

modBuilder = asmBuilder.DefineDynamicModule("Abstract");

Define a class. In this example, the class is named Sample.

TypeBuilder CreateType(ModuleBuilder modBuilder, string typeName)
{
    TypeBuilder typeBuilder = modBuilder.DefineType(typeName,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                typeof(object));
    return typeBuilder;
}

Define the generic type parameters of Sample by passing an array of strings containing the names of the parameters to the TypeBuilder.DefineGenericParameters method. This makes the class a generic type. The return value is an array of GenericTypeParameterBuilder objects representing the type parameters, which can be used in your emitted code.


In the following code, Sample becomes a generic type with type parameters TFirst and TSecond. To make the code easier to read, each GenericTypeParameterBuilder is placed in a variable with the same name as the type parameter.

A property is defined using the TypeBuilder.DefineProperty method. DefineProperty returns a PropertyBuilder. The DefineProperty method requires the caller to specify the property name, the signature of the property, the property attributes (using the PropertyAttributes enumeration), and the backing field.


The PropertyBuilder class allows the caller to specify the getter method, the setter method, and any other methods.



void CreateProperty(TypeBuilder t, string name, Type typ)
{
    string field = "_" + name.ToLower();
    FieldBuilder fieldBldr = t.DefineField(field, typ, FieldAttributes.Private);
    PropertyBuilder propBldr = t.DefineProperty(name, System.Reflection.PropertyAttributes.HasDefault, typ, null);
    MethodAttributes getSetAttr = MethodAttributes.Public |
    MethodAttributes.SpecialName |
    MethodAttributes.HideBySig;

    MethodBuilder getPropBldr = t.DefineMethod("get_" + name, getSetAttr, typ, Type.EmptyTypes);

    ILGenerator getIL = getPropBldr.GetILGenerator();
    getIL.Emit(OpCodes.Ldarg_0);
    getIL.Emit(OpCodes.Ldfld, fieldBldr);
    getIL.Emit(OpCodes.Ret);
    MethodBuilder setPropBldr = t.DefineMethod("set_" + name, getSetAttr, null, new Type[] { typ });

    ILGenerator setIL = setPropBldr.GetILGenerator();

    setIL.Emit(OpCodes.Ldarg_0);
    setIL.Emit(OpCodes.Ldarg_1);
    setIL.Emit(OpCodes.Stfld, fieldBldr);
    setIL.Emit(OpCodes.Ret);

    propBldr.SetGetMethod(getPropBldr);
    propBldr.SetSetMethod(setPropBldr);

}
//Create Dyanamic Property by the Name and Type
CreateProperty(“TFirst”,String);
CreateProperty(“TSecond”,String);

Example

The following code example defines a class named from a DataTable (Name of the table), along with a base class and properties as the column name of that DataTable. The program defines generic type parameters for the Class, turning it into a generic type. Type parameters are the only thing that makes a type generic. The program gets the generic List of Data as the DataTable return.


namespace Generic.Data
{
    public partial class GenericBase
    {
        #region [ ObjectCollection ]
        /// <summary>
        /// Get Object Collection by DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="P"></typeparam>
        /// <param name="DataSet"></param>
        /// <returns>P</returns>
        protected List<T> ObjectCollection<T>(DataTable ds)
            where T : GenericObject
        {
            GenericBase oo = new GenericBase();
            oo.GenerateAssemblyAndModule();
            Type finalType;
            TypeBuilder tb = oo.CreateType(ds.TableName);

            //Create Dyanamic Property by the Table Column
            for (int AttIndex = 0; AttIndex < ds.Columns.Count; AttIndex++)
                oo.CreateProperty(tb, ds.Columns[AttIndex].ColumnName, ds.Columns[AttIndex].DataType);

            //Create Dyanamic Class by the Table Name
            finalType = tb.CreateType();

            List<T> _CollectioObj = null;
            Object _Obj = null;

            if (ds != null && ds.Rows.Count > 0)
            {
                _CollectioObj = (List<T>)Activator.CreateInstance(typeof(List<T>));
                for (int RowIndex = 0; RowIndex < ds.Rows.Count; RowIndex++)
                {
                    _Obj = (T)Activator.CreateInstance(finalType);
                    for (int AttIndex = 0; AttIndex < ds.Columns.Count; AttIndex++)
                    {
                        try
                        {
                            //Set the value of Dynamic Properties
                            object DBValue = ds.Rows[RowIndex][ds.Columns[AttIndex].ColumnName];
                            if (finalType.GetProperty(ds.Columns[AttIndex].ColumnName) != null)
                                finalType.GetProperty(ds.Columns[AttIndex].ColumnName).SetValue(_Obj, DBValue.GetType() == typeof(DBNull) ? null : DBValue, null);
                        }
                        catch
                        {
                            new NullReferenceException(ds.Columns[AttIndex].ColumnName + " Dynamic Properties not found");
                        }
                    }
                    typeof(List<T>).GetMethod("Add").Invoke(_CollectioObj, new object[] { _Obj });
                }
            }
            return _CollectioObj;
        }
        #endregion

        #region [ Type Reflection ]
        AssemblyBuilder asmBuilder
        {
            get;
            set;
        }
        ModuleBuilder modBuilder
        {
            get;
            set;
        }
        void GenerateAssemblyAndModule()
        {
            if (asmBuilder == null)
            {
                AppDomain myDomain = AppDomain.CurrentDomain;
                AssemblyName myAsmName = new AssemblyName("Generic.Data");
                asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
                // An assembly is made up of executable modules. For a single-
                // module assembly, the module name and file name are the same
                // as the assembly name.
                modBuilder = asmBuilder.DefineDynamicModule("Abstract");
            }
        }
        TypeBuilder CreateType(ModuleBuilder modBuilder, string typeName)
        {
            TypeBuilder typeBuilder = modBuilder.DefineType(typeName,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout,
                        typeof(object));
            return typeBuilder;
        }
        TypeBuilder CreateType(string typeName)
        {
            TypeBuilder typeBuilder = modBuilder.DefineType(typeName,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout,
                        typeof(GenericObject));
            return typeBuilder;
        }
        void CreateProperty(TypeBuilder t, string name, Type typ)
        {
            string field = "_" + name.ToLower();
            FieldBuilder fieldBldr = t.DefineField(field, typ, FieldAttributes.Private);
            PropertyBuilder propBldr = t.DefineProperty(name, System.Reflection.PropertyAttributes.HasDefault, typ, null);
            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

            MethodBuilder getPropBldr = t.DefineMethod("get_" + name, getSetAttr, typ, Type.EmptyTypes);

            ILGenerator getIL = getPropBldr.GetILGenerator();
            getIL.Emit(OpCodes.Ldarg_0);
            getIL.Emit(OpCodes.Ldfld, fieldBldr);
            getIL.Emit(OpCodes.Ret);

            MethodBuilder setPropBldr = t.DefineMethod("set_" + name, getSetAttr, null, new Type[] { typ });

            ILGenerator setIL = setPropBldr.GetILGenerator();

            setIL.Emit(OpCodes.Ldarg_0);
            setIL.Emit(OpCodes.Ldarg_1);
            setIL.Emit(OpCodes.Stfld, fieldBldr);
            setIL.Emit(OpCodes.Ret);

            propBldr.SetGetMethod(getPropBldr);
            propBldr.SetSetMethod(setPropBldr);

        }
        #endregion
    }
    public partial class GenericObject : Object
    {
        /// <summary>
        /// Get or set the value of Property
        /// </summary>
        /// <param name="PropertyName"></param>
        /// <returns>Object</returns>
        public Object this[string s]
        {
            get
            {
                return this.GetType().GetProperty(s).GetValue(this, null);
            }
            set
            {
                this.GetType().GetProperty(s).SetValue(this, value.GetType() == typeof(DBNull) ? null : value, null);
            }
        }
    }

public class GetData : Generic.Data.GenericBase
    {
        public List<GenericObject>  Data()
        {
            base.ConnectionString = "Server=yourserver;Database=yourdb;User Id =sa;Password =;Integrated Security=false";
            base.Provider = GenericProvider.SqlServer;
            Farvision.Sales.BL.clsCommon oo = new Farvision.Sales.BL.clsCommon();
            DataSet dsData = oo.GetDataSet(HttpContext.Current.Session.Contents["ConnectionInfo"].ToString(),
                          HttpContext.Current.Session.Contents["Provider"].ToString(),
                          "SELECT DISTINCT top 10 B.DESCR,ACCD,DOCNO FROM M_SALE A INNER JOIN M_ITEM B ON A.ITEMCD = B.ITEMCD ORDER BY B.DESCR,ACCD,DOCNO");

            List<GenericObject> _coll = ObjectCollection<GenericObject>(dsData.Tables[0]);
           
            //Object dd = _coll[0]["DESCR"];
            return _coll;
        }
    }
}


Posted By: Mr. Palash Paul

1 comment:

  1. Excellent Post with understandable example for Beginners.
    Waiting for more...........

    ReplyDelete