Exemple #1
0
        /// <summary>
        /// Generates an accessor for a property in the object.
        /// </summary>
        /// <param name="type">The type of object being read.</param>
        /// <param name="mapping">The column mapping.</param>
        /// <param name="columnInfo">The column information.</param>
        /// <returns>An accessor function or null if there is no mapping.</returns>
        private static Func <object, object> GenerateAccessor(Type type, FieldMapping mapping, ColumnInfo columnInfo)
        {
            // create a new anonymous method that takes an object and returns the value
            var dm = new DynamicMethod(string.Format(CultureInfo.InvariantCulture, "GetValue-{0}-{1}", type.FullName, Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);
            var il = dm.GetILGenerator();

            // convert the object reference to the desired type
            il.Emit(OpCodes.Ldarg_0);

            var readyToSetLabel = il.DefineLabel();

            // get the value from the object
            Type sourceType;

            if (mapping != null)
            {
                if (type.GetTypeInfo().IsValueType)
                {
                    // access the field/property of a value type
                    var valueHolder = il.DeclareLocal(type);
                    il.Emit(OpCodes.Unbox_Any, type);
                    il.Emit(OpCodes.Stloc, valueHolder);
                    il.Emit(OpCodes.Ldloca_S, valueHolder);
                }
                else
                {
                    il.Emit(OpCodes.Isinst, type);                                      // cast object -> type
                }

                ClassPropInfo.EmitGetValue(type, mapping.PathToMember, il, readyToSetLabel);
                if (mapping.Member.MemberType.GetTypeInfo().IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, mapping.Member.MemberType);
                }

                ClassPropInfo propInfo = mapping.Member;
                sourceType = propInfo.MemberType;

                // if the type is nullable, handle nulls
                Type underlyingType = Nullable.GetUnderlyingType(sourceType);
                if (underlyingType != null)
                {
                    // check for not null
                    Label notNullLabel = il.DefineLabel();

                    var nullableHolder = il.DeclareLocal(propInfo.MemberType);
                    il.Emit(OpCodes.Stloc, nullableHolder);
                    il.Emit(OpCodes.Ldloca_S, nullableHolder);
                    il.Emit(OpCodes.Call, sourceType.GetProperty("HasValue").GetGetMethod());
                    il.Emit(OpCodes.Brtrue_S, notNullLabel);

                    // it's null, just return null
                    il.Emit(OpCodes.Ldnull);
                    il.Emit(OpCodes.Ret);

                    il.MarkLabel(notNullLabel);

                    // it's not null, so unbox to the underlyingtype
                    il.Emit(OpCodes.Ldloca, nullableHolder);
                    il.Emit(OpCodes.Call, sourceType.GetProperty("Value").GetGetMethod());

                    // at this point we have de-nulled value, so use those converters
                    sourceType = underlyingType;
                }
            }
            else
            {
                // there is no mapping, so we're going to convert the object itself to the target type
                sourceType = type;

                // if the value is null then exit immediately
                var notNullLabel = il.DefineLabel();
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Brfalse, readyToSetLabel);
                il.MarkLabel(notNullLabel);

                // we get it as an object. unbox it so we can apply conversion operations
                if (sourceType.GetTypeInfo().IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, sourceType);
                }
            }

            // if the serializer isn't the default ToStringSerializer, and it can serialize the type properly, then use it
            // otherwise we'll use coersion or conversion
            Type targetType   = columnInfo.DataType;
            var  targetDbType = DbParameterGenerator.LookupDbType(targetType);
            bool canSerialize = sourceType != typeof(string) &&
                                mapping != null &&
                                mapping.Serializer.GetType() != typeof(ToStringObjectSerializer) &&
                                mapping.Serializer.CanSerialize(sourceType, targetDbType);

            // attempt to convert the value
            var currentType = sourceType;

            if (currentType != targetType)
            {
                if (canSerialize)
                {
                    if (sourceType.GetTypeInfo().IsValueType)
                    {
                        il.Emit(OpCodes.Box, sourceType);
                    }
                    il.EmitLoadType(sourceType);
                    StaticFieldStorage.EmitLoad(il, mapping.Serializer);
                    il.Emit(OpCodes.Call, typeof(ObjectReader).GetMethod("SerializeObject", BindingFlags.NonPublic | BindingFlags.Static));

                    currentType = typeof(Object);
                }
                else if (TypeConverterGenerator.EmitConversionOrCoersion(il, sourceType, targetType))
                {
                    currentType = targetType;
                }
            }

            // either way, we are putting it in an object variable, so box it
            if (currentType.GetTypeInfo().IsValueType)
            {
                il.Emit(OpCodes.Box, currentType);
            }

            il.MarkLabel(readyToSetLabel);
            il.Emit(OpCodes.Ret);

            return((Func <object, object>)dm.CreateDelegate(typeof(Func <object, object>)));
        }
 /// <summary>
 /// Reads the schema from a data reader.
 /// </summary>
 /// <param name="reader">The reader to process.</param>
 private void ReadSchema(IDataReader reader)
 {
     _columns = ColumnInfo.FromDataReader(reader);
 }