예제 #1
0
        private static Action <DbDataReader, T> GenerateAssignment <T>(INameResolver nameResolver, DbDataReader reader) where T : new()
        {
            var expressions = new List <Expression>();

            var t             = typeof(T);
            var targetParam   = Expression.Parameter(t);
            var valueVariable = Expression.Variable(typeof(object));
            var readerParam   = Expression.Parameter(typeof(DbDataReader));

            var getValueMethod = typeof(DbDataReader).GetTypeInfo().GetMethod("GetValue");

            #if DEBUG
            var exceptionConstructor = typeof(InvalidCastException).GetConstructor(new [] { typeof(string), typeof(Exception) });
            var exceptParam          = Expression.Parameter(typeof(Exception));
            #endif

            for (var i = 0; i < reader.VisibleFieldCount; i++)
            {
                var dbName     = reader.GetName(i);
                var csharpName = nameResolver.DbToCSharp(dbName);

                expressions.Add(Expression.Assign(valueVariable, Expression.Call(readerParam, getValueMethod, Expression.Constant(i))));

                Expression notNullBranch = null;

                if (csharpName == t.Name)
                {
                    csharpName += "F";
                }

                var field = t.GetTypeInfo().GetField(csharpName);

                if (field != null)
                {
                    var fi = field.FieldType.GetTypeInfo();

                    foreach (var tcs in TypeConversionSpecializationsWithDefault)
                    {
                        if (tcs.Matches(fi, field.FieldType))
                        {
#if DEBUG
                            notNullBranch = Expression.TryCatch(
                                Expression.Assign(
                                    Expression.Field(targetParam, field),
                                    tcs.Convert(fi, field.FieldType, valueVariable)
                                    ),
                                Expression.Catch(exceptParam, Expression.Throw(Expression.New(exceptionConstructor, Expression.Constant(field.Name), exceptParam), field.FieldType))
                                );
#else
                            notNullBranch = Expression.Assign(
                                Expression.Field(targetParam, field),
                                tcs.Convert(fi, field.FieldType, valueVariable)
                                );
#endif
                            break;
                        }
                    }
                }
                else
                {
                    var property = t.GetTypeInfo().GetProperty(csharpName);

                    if (property == null)
                    {
                        throw new ArgumentException($"field or property {csharpName} on type {t} not found for database column {dbName}");
                    }

                    var ti = property.PropertyType.GetTypeInfo();

                    foreach (var tcs in TypeConversionSpecializationsWithDefault)
                    {
                        if (tcs.Matches(ti, property.PropertyType))
                        {
#if DEBUG
                            notNullBranch = Expression.TryCatch(
                                Expression.Assign(
                                    Expression.Property(targetParam, property),
                                    tcs.Convert(ti, property.PropertyType, valueVariable)
                                    ),
                                Expression.Catch(exceptParam, Expression.Throw(Expression.New(exceptionConstructor, Expression.Constant(property.Name), exceptParam), property.PropertyType))
                                );
#else
                            notNullBranch = Expression.Assign(
                                Expression.Property(targetParam, property),
                                tcs.Convert(ti, property.PropertyType, valueVariable)
                                );
#endif
                            break;
                        }
                    }
                }

                var dbNullTest = Expression.Equal(valueVariable, Expression.Constant(DBNull.Value));

                expressions.Add(Expression.IfThen(Expression.IsFalse(dbNullTest), notNullBranch));
            }

            var block = Expression.Block(
                new[] {
                valueVariable
            },
                expressions.ToArray()
                );

            var action = Expression.Lambda <Action <DbDataReader, T> >(block, readerParam, targetParam).Compile();
            return(action);
        }