Example #1
0
        /// <summary>
        /// Searches the type and child types for a field that matches the given column name.
        /// </summary>
        /// <param name="type">The type to search.</param>
        /// <param name="columnName">The column to search for.</param>
        /// <param name="mappingCollection">The mapping collection containing the configuration for this context.</param>
        /// <returns>The name of the field or null if there is no match.</returns>
        internal static string SearchForMatchingField(Type type, string columnName, MappingCollection mappingCollection)
        {
            var queue = new Queue <Tuple <Type, string> >();

            queue.Enqueue(Tuple.Create(type, String.Empty));

            var searched = new HashSet <Type>();

            while (queue.Any())
            {
                var tuple  = queue.Dequeue();
                var t      = tuple.Item1;
                var prefix = tuple.Item2;
                searched.Add(t);

                var prop = GetMemberByColumnName(t, columnName);
                if (prop != null)
                {
                    return(prefix + prop.Name);
                }

                if (mappingCollection.CanBindChild(t))
                {
                    foreach (var p in ClassPropInfo.GetMembersForType(t).Where(m => !TypeHelper.IsAtomicType(m.MemberType)))
                    {
                        if (!searched.Contains(p.MemberType))
                        {
                            queue.Enqueue(Tuple.Create(p.MemberType, prefix + p.Name + MemberSeparator));
                        }
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Uses IL to generate a method that converts an object of a given type to a FastExpando.
        /// </summary>
        /// <param name="type">The type of object to be able to convert.</param>
        /// <returns>A function that can convert that type of object to a FastExpando.</returns>
        private static Func <object, FastExpando> CreateConverter(Type type)
        {
            // create a dynamic method
            var dm = new DynamicMethod(String.Format(CultureInfo.InvariantCulture, "ExpandoGenerator-{0}", type.FullName), typeof(FastExpando), new[] { typeof(object) }, typeof(ExpandoGenerator), true);

            var il     = dm.GetILGenerator();
            var source = il.DeclareLocal(type);

            // load the parameter object onto the stack and convert it into the local variable
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Castclass, type);
            il.Emit(OpCodes.Stloc, source);

            // new instance of fastexpando                                  // top of stack
            il.Emit(OpCodes.Newobj, _constructor);

            // for each public field or method, get the value
            foreach (ClassPropInfo accessor in ClassPropInfo.GetMembersForType(type).Where(m => m.CanGetMember))
            {
                il.Emit(OpCodes.Dup);                                                                           // push expando - so we can call set value
                il.Emit(OpCodes.Ldstr, accessor.Name);                                                          // push name

                // get the value of the field or property
                il.Emit(OpCodes.Ldloc, source);
                accessor.EmitGetValue(il);

                // value types need to be boxed
                if (accessor.MemberType.GetTypeInfo().IsValueType)
                {
                    il.Emit(OpCodes.Box, accessor.MemberType);
                }

                // call expando.setvalue
                il.Emit(OpCodes.Callvirt, _fastExpandoSetValue);
            }

            // return expando - it should be left on the stack
            il.Emit(OpCodes.Ret);

            return((Func <object, FastExpando>)dm.CreateDelegate(typeof(Func <object, FastExpando>)));
        }
Example #3
0
        /// <summary>
        /// Creates a deserializer for a graph of objects.
        /// </summary>
        /// <param name="subTypes">The types of the subobjects.</param>
        /// <param name="reader">The reader to analyze.</param>
        /// <param name="structure">The structure of the record we are reading.</param>
        /// <param name="allowBindChild">True if the columns should be allowed to bind to children.</param>
        /// <returns>A function that takes an IDataReader and deserializes an object of type T.</returns>
        private static Delegate CreateGraphDeserializer(Type[] subTypes, IDataReader reader, IRecordStructure structure, bool allowBindChild)
        {
            Type type     = subTypes[0];
            bool isStruct = type.GetTypeInfo().IsValueType;

            // go through each of the subtypes
            var deserializers = CreateDeserializersForSubObjects(subTypes, reader, structure, allowBindChild);

            // create a new anonymous method that takes an IDataReader and returns T
            var dm = new DynamicMethod(
                String.Format(CultureInfo.InvariantCulture, "Deserialize-{0}-{1}", type.FullName, Guid.NewGuid()),
                type,
                new[] { typeof(IDataReader) },
                true);
            var il          = dm.GetILGenerator();
            var localObject = il.DeclareLocal(type);

            // keep track of the properties that we have already used
            // the tuple is the level + property
            var usedMethods = new HashSet <Tuple <int, ClassPropInfo> >();

            ///////////////////////////////////////////////////
            // emit the method
            ///////////////////////////////////////////////////
            for (int i = 0; i < deserializers.Length; i++)
            {
                // if there is no deserializer for this object, then skip it
                if (deserializers[i] == null)
                {
                    continue;
                }

                // for subobjects, dup the core object so we can set values on it
                if (i > 0)
                {
                    if (isStruct)
                    {
                        il.Emit(OpCodes.Ldloca_S, localObject);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldloc, localObject);
                    }
                }

                // if we don't have a callback, then we are going to store the value directly into the field on T or one of the subobjects
                // here we determine the proper set method to store into.
                // we are going to look into all of the types in the graph and find the first parameter that matches our current type
                ClassPropInfo setMethod = null;
                for (int parent = 0; parent < i; parent++)
                {
                    // find the set method on the current parent
                    setMethod = GetFirstMatchingMethod(ClassPropInfo.GetMembersForType(subTypes[parent]).Where(m => m.CanSetMember), subTypes[i]);

                    // make sure that at a given level, we only use the method once
                    var tuple = Tuple.Create(parent, setMethod);
                    if (usedMethods.Contains(tuple))
                    {
                        continue;
                    }
                    else
                    {
                        usedMethods.Add(tuple);
                    }

                    // if we didn't find a matching set method, then continue on to the next type in the graph
                    if (setMethod == null)
                    {
                        continue;
                    }

                    // if the parent is not the root object, we have to drill down to the parent, then set the value
                    // the root object is already on the stack, so emit a get method to get the object to drill down into
                    for (int p = 0; p < parent; p++)
                    {
                        var getMethod = GetFirstMatchingMethod(ClassPropInfo.GetMembersForType(subTypes[p]).Where(m => m.CanGetMember && m.CanSetMember), subTypes[p + 1]);
                        if (getMethod == null)
                        {
                            throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "In order to deserialize sub-objects, {0} must have a get/set method for type {1}", subTypes[p].FullName, subTypes[p + 1].FullName));
                        }
                        getMethod.EmitGetValue(il);
                    }

                    break;
                }

                // call the deserializer for the subobject
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Call, deserializers[i]);

                // other than the root object, set the value on the parent object
                if (i == 0)
                {
                    // store root object in loc.0
                    il.Emit(OpCodes.Stloc, localObject);
                }
                else
                {
                    if (setMethod == null)
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot find set method for type {0} into type {1}", subTypes[i].FullName, subTypes[0].FullName));
                    }

                    setMethod.EmitSetValue(il);
                }
            }

            // return the object from loc.0
            il.Emit(OpCodes.Ldloc, localObject);
            il.Emit(OpCodes.Ret);

            // convert the dynamic method to a delegate
            var delegateType = typeof(Func <,>).MakeGenericType(typeof(IDataReader), type);

            return(dm.CreateDelegate(delegateType));
        }