Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Matthieu MEZIL

I love .Net

Abonnements

Actualités

Locations of visitors to this page English blog
Locations of visitors to this blog
LINQ To SQL Table -> DataTable, génération de code à la volée, V3

Suite à la nouvelle remarque de Jean-Baptiste, mon code devient finalement ceci :

namespace ConsoleApplication81

{

    class Program

    {

        static void Main(string[] args)

        {

            using (var context = new DataClasses1DataContext())

            {

                var dt = LinqTableToDataTableHelper<Category>.GetDataTableFromLINQTable(context.Categories);

            }

        }

    }

    public static class LinqTableToDataTableHelper<LTT>

            where LTT : class

    {

        private static Func<Table<LTT>, DataTable> _generatedMethodDelegate;

 

        public static DataTable GetDataTableFromLINQTable(Table<LTT> linqTable)

        {

            if (_generatedMethodDelegate == null)

                _generatedMethodDelegate = GenerateTableConverter().CreateDelegate(typeof(Func<Table<LTT>, DataTable>)) as Func<Table<LTT>, DataTable>;

            return _generatedMethodDelegate(linqTable);

        }

 

        public static DynamicMethod GenerateTableConverter()

        {

            var dynamicMethod = new DynamicMethod("Convert", typeof(DataTable), new Type[] { typeof(Table<LTT>) });

            var convertIlGenerator = dynamicMethod.GetILGenerator();

            convertIlGenerator.DeclareLocal(typeof(DataTable));

            convertIlGenerator.DeclareLocal(typeof(IEnumerator<LTT>));

            convertIlGenerator.DeclareLocal(typeof(LTT));

            convertIlGenerator.DeclareLocal(typeof(DataRow));

            var propertyValue = convertIlGenerator.DeclareLocal(typeof(object));

            convertIlGenerator.Emit(OpCodes.Ldarg_0);

            var convertIlGeneratorArgOkLabel = convertIlGenerator.DefineLabel();

            convertIlGenerator.Emit(OpCodes.Brtrue_S, convertIlGeneratorArgOkLabel);

            convertIlGenerator.Emit(OpCodes.Newobj, typeof(ArgumentException).GetConstructor(new Type[0]));

            convertIlGenerator.Emit(OpCodes.Throw);

            convertIlGenerator.MarkLabel(convertIlGeneratorArgOkLabel);

 

            convertIlGenerator.Emit(OpCodes.Newobj, typeof(DataTable).GetConstructor(new Type[0]));

            convertIlGenerator.Emit(OpCodes.Stloc_0);

            var properties = typeof(LTT).GetProperties().Where(p => p.GetAttribute<ColumnAttribute>() != null);

            foreach (var pi in properties)

            {

                convertIlGenerator.Emit(OpCodes.Ldloc_0);

                convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataTable).GetMethod("get_Columns"));

                convertIlGenerator.Emit(OpCodes.Ldstr, pi.Name);

                if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))

                    convertIlGenerator.Emit(OpCodes.Ldtoken, pi.PropertyType.GetGenericArguments()[0]);

                else

                    convertIlGenerator.Emit(OpCodes.Ldtoken, pi.PropertyType);

                convertIlGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));

                convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataColumnCollection).GetMethod("Add", new Type[] { typeof(string), typeof(Type) }));

                convertIlGenerator.Emit(OpCodes.Pop);

            }

            var convertIlGeneratorEntitiesLoopLabel = convertIlGenerator.DefineLabel();

            convertIlGenerator.Emit(OpCodes.Ldarg_0);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(IEnumerable<LTT>).GetMethod("GetEnumerator"));

            convertIlGenerator.Emit(OpCodes.Stloc_1);

            convertIlGenerator.MarkLabel(convertIlGeneratorEntitiesLoopLabel);

            convertIlGenerator.Emit(OpCodes.Ldloc_1);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(IEnumerator).GetMethod("MoveNext"));

            var convertIlGeneratorEntitiesEndLoopLable = convertIlGenerator.DefineLabel();

            convertIlGenerator.Emit(OpCodes.Brfalse, convertIlGeneratorEntitiesEndLoopLable);

            convertIlGenerator.Emit(OpCodes.Ldloc_1);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(IEnumerator<LTT>).GetMethod("get_Current"));

            convertIlGenerator.Emit(OpCodes.Stloc_2);

            convertIlGenerator.Emit(OpCodes.Ldloc_0);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataTable).GetMethod("get_Rows"));

            convertIlGenerator.Emit(OpCodes.Ldloc_0);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataTable).GetMethod("NewRow"));

            convertIlGenerator.Emit(OpCodes.Stloc_3);

            foreach (var pi in properties)

            {

                convertIlGenerator.Emit(OpCodes.Ldloc_2);

                convertIlGenerator.Emit(OpCodes.Callvirt, typeof(LTT).GetMethod("get_" + pi.Name, new Type[0]));

                if (pi.PropertyType.IsValueType)

                    convertIlGenerator.Emit(OpCodes.Box, pi.PropertyType);

                convertIlGenerator.Emit(OpCodes.Stloc, propertyValue);

                convertIlGenerator.Emit(OpCodes.Ldloc, propertyValue);

                var convertIlGeneratorNextPropertyLabel = convertIlGenerator.DefineLabel();

                convertIlGenerator.Emit(OpCodes.Brfalse_S, convertIlGeneratorNextPropertyLabel);

                convertIlGenerator.Emit(OpCodes.Ldloc_3);

                convertIlGenerator.Emit(OpCodes.Ldstr, pi.Name);

                convertIlGenerator.Emit(OpCodes.Ldloc, propertyValue);

                convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataRow).GetMethod("set_Item", new Type[] { typeof(string), typeof(object) }));

                convertIlGenerator.MarkLabel(convertIlGeneratorNextPropertyLabel);

            }

            convertIlGenerator.Emit(OpCodes.Ldloc_3);

            convertIlGenerator.Emit(OpCodes.Callvirt, typeof(DataRowCollection).GetMethod("Add", new Type[] { typeof(DataRow) }));

            convertIlGenerator.Emit(OpCodes.Br, convertIlGeneratorEntitiesLoopLabel);

            convertIlGenerator.MarkLabel(convertIlGeneratorEntitiesEndLoopLable);

            convertIlGenerator.Emit(OpCodes.Ldloc_0);

            convertIlGenerator.Emit(OpCodes.Ret);

 

            return dynamicMethod;

        }

    }

}

namespace System.Reflection

{

    public static class PropertyInfoExtension

    {

        public static T GetAttribute<T>(this PropertyInfo pi) where T : Attribute

        {

            object[] attributes = pi.GetCustomAttributes(typeof(T), true);

            if (attributes.Length == 0)

                return null;

            return attributes[0] as T;

        }

    }

}

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié lundi 14 avril 2008 17:49 par Matthieu MEZIL

Classé sous : , , , ,

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- un Pacman en Silverlight 2b2 par Pierrick's Blog le il y a 4 heures et 35 minutes

- Une table -> deux entity types sans colonne discriminante en base, gestion des relations par Matthieu MEZIL le il y a 12 heures et 33 minutes

- ssdl view et TPT par Matthieu MEZIL le 07-05-2008, 02:04

- L'injection SQL n'est PAS un problème QUE pour les développeurs web ! par CoqBlog le 07-05-2008, 01:08

- Un outil pour réaliser des animations WPF basées sur des équations de Bézier par Perspective le 07-04-2008, 21:45

- Sandcastle et CodePlex : le verdict par CoqBlog le 07-04-2008, 20:53

- ssdl view et TPH par Matthieu MEZIL le 07-04-2008, 19:12

- Webcasts sur le Parallel Framework disponibles par Matthieu MEZIL le 07-04-2008, 17:26

- [Silverlight] - Comprendre et Débuter avec Silverlight par Danuz le 07-04-2008, 12:41

- SharePoint : Nouvel article sur l'exportation et Importation de sites SharePoint par Blog Technique de Romelard Fabrice le 07-04-2008, 01:00