Пример #1
0
        /// <summary>
        /// cache assembly interfaces
        /// </summary>
        /// <param name="assembly">assembly to cache</param>
        internal static void CacheAssembly(Assembly assembly)
        {
            // collect all db interfaces in assembly and create concrete
            // types for them then store all required information
            // for fast access when needed

            Type[] interfaces = assembly.GetTypes().Where(t => t.IsInterface).ToArray();

            // stage 1: load basic information for all types and their dependencies
            foreach (var item in interfaces)
            {
                if (interfaceCache.ContainsKey(item.GUID))
                {
                    if (interfaceCache[item.GUID].InterfaceType.AssemblyQualifiedName == item.AssemblyQualifiedName)
                    {
                        continue;
                    }

                    throw new InvalidOperationException($"Internal Error, interface {item.Name} have GUID similar to another loaded interface from other assembly");
                }

                InterfaceMetadata itemMeta = GetInterfaceBasicInformation(item);
                if (itemMeta == null)
                {
                    continue;
                }

                interfaceCache.Add(item.GUID, itemMeta);

                // load type dependencies
                foreach (var parent in item.GetInterfaces())
                {
                    InterfaceMetadata meta = null;
                    if (interfaceCache.ContainsKey(parent.GUID))
                    {
                        meta = interfaceCache[parent.GUID];
                    }
                    else
                    {
                        meta = GetInterfaceBasicInformation(parent);

                        if (meta == null)
                        {
                            throw new TypeLoadException($"Interface '{parent.Name}' is used by other interfaces and don't marked by ConcreteAttribute");
                        }

                        interfaceCache.Add(parent.GUID, meta);
                    }

                    itemMeta.Parents.Add(meta);
                }
            }

            // stage 2: create dynamic types
            foreach (var item in interfaceCache.Values.Where(e => e.Concrete == null))
            {
                item.Concrete = ImplementInterface(item);
            }
        }
Пример #2
0
        /// <summary>
        /// get interface metadata
        /// </summary>
        /// <param name="interfaceType">type to get its metadata</param>
        /// <returns>return type metadata for input type; null for invalid type</returns>
        /// <remarks>an invalid type is an non-interface type.</remarks>
        public static InterfaceMetadata GetInterface(Type interfaceType)
        {
            if (interfaceCache.ContainsKey(interfaceType.GUID))
            {
                return(interfaceCache[interfaceType.GUID]);
            }

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException($"Type {interfaceType.Name} is not an interface");
            }

            InterfaceMetadata itemMeta = GetInterfaceBasicInformation(interfaceType);

            if (itemMeta == null)
            {
                throw new TypeLoadException($"Interface '{interfaceType.Name}' is not marked with ConcreteAttribute");
            }

            interfaceCache.Add(interfaceType.GUID, itemMeta);

            Type[] interfaces = interfaceType.GetInterfaces();

            // load type dependencies
            foreach (var parent in interfaces)
            {
                InterfaceMetadata meta = null;
                if (interfaceCache.ContainsKey(parent.GUID))
                {
                    meta = interfaceCache[parent.GUID];
                }
                else
                {
                    meta = GetInterfaceBasicInformation(parent);

                    if (meta == null)
                    {
                        throw new TypeLoadException($"Interface '{parent.Name}' is used by other interfaces and don't marked by ConcreteAttribute");
                    }

                    interfaceCache.Add(parent.GUID, meta);
                }

                itemMeta.Parents.Add(meta);
            }

            if (itemMeta.Concrete == null)
            {
                itemMeta.Concrete = ImplementInterface(itemMeta);
            }

            foreach (var item in itemMeta.Parents.Where(e => e.Concrete == null))
            {
                item.Concrete = ImplementInterface(item);
            }

            return(itemMeta);
        }
Пример #3
0
        /// <summary>
        /// implement interface and its dependencies into class
        /// </summary>
        /// <param name="interfaceMeta">interface metadata</param>
        /// <returns>return generated class that implement input interface</returns>
        private static Type ImplementInterface(InterfaceMetadata interfaceMeta)
        {
            TypeBuilder resultType = module.DefineType($"{interfaceMeta.Name}_{Guid.NewGuid().ToString("N")}", TypeAttributes.Class | TypeAttributes.Public, typeof(object), null);

            var interfaces = new List <InterfaceMetadata>(interfaceMeta.Parents);

            interfaces.Insert(0, interfaceMeta);

            foreach (var item in interfaces)
            {
                resultType.AddInterfaceImplementation(interfaceMeta.InterfaceType);

                foreach (var property in item.Properties)
                {
                    FieldBuilder    field = resultType.DefineField($"m{property.Name}", property.Type, FieldAttributes.Private);
                    PropertyBuilder prop  = resultType.DefineProperty($"{interfaceMeta.InterfaceType.FullName}.{property.Name}",
                                                                      System.Reflection.PropertyAttributes.None, CallingConventions.HasThis, property.Type, Type.EmptyTypes);

                    MethodBuilder getMethod = resultType.DefineMethod($"{interfaceMeta.InterfaceType.FullName}.get_{property.Name}",
                                                                      MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName |
                                                                      MethodAttributes.Virtual | MethodAttributes.Final, property.Type, Type.EmptyTypes);

                    ILGenerator getGen = getMethod.GetILGenerator();
                    getGen.Emit(OpCodes.Ldarg_0);
                    getGen.Emit(OpCodes.Ldfld, field);
                    getGen.Emit(OpCodes.Ret);

                    MethodBuilder setMethod = resultType.DefineMethod($"{interfaceMeta.InterfaceType.FullName}.set_{property.Name}",
                                                                      MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName |
                                                                      MethodAttributes.Virtual | MethodAttributes.Final, null, new[] { property.Type });

                    ILGenerator setGen = setMethod.GetILGenerator();
                    setGen.Emit(OpCodes.Ldarg_0);
                    setGen.Emit(OpCodes.Ldarg_1);
                    setGen.Emit(OpCodes.Stfld, field);
                    setGen.Emit(OpCodes.Ret);

                    prop.SetGetMethod(getMethod);
                    resultType.DefineMethodOverride(getMethod, property.GetMethod);
                    prop.SetSetMethod(setMethod);
                    resultType.DefineMethodOverride(setMethod, property.SetMethod);
                }
            }

            return(resultType.CreateType());
        }
Пример #4
0
        /// <summary>
        /// get interface basic meta data
        /// </summary>
        /// <param name="interfaceType">interface to get metadata</param>
        /// <returns>return basic metadata for interface</returns>
        private static InterfaceMetadata GetInterfaceBasicInformation(Type interfaceType)
        {
            var concreteAttrib = (ConcreteAttribute[])interfaceType.GetCustomAttributes(typeof(ConcreteAttribute), false);

            if (concreteAttrib.Length == 0)
            {
                return(null);
            }

            var meta = new InterfaceMetadata
            {
                Id            = interfaceType.GUID,
                Name          = interfaceType.Name,
                InterfaceType = interfaceType,
                Properties    = GetInterfaceProperties(interfaceType, concreteAttrib[0].Type == null),
                Parents       = new List <InterfaceMetadata>(),
                Concrete      = concreteAttrib[0].Type
            };

            meta.UpdateMetadata();

            return(meta);
        }
Пример #5
0
        internal static void ReadMultiResultset(IDataReader reader, object instance, InterfaceMetadata metaData, string[] properties)
        {
            for (int index = 0; ; ++index)
            {
                if (properties.Length <= index)
                {
                    throw new ArgumentException("input properties are fewer than number of result set");
                }

                PropertyMetadata property = metaData.GetProperty(properties[index], true);

                // check if result rest is a IEnumerable (only IList is supported)
                if (property.Type.IsGenericType && (property.Type.GetGenericTypeDefinition() == typeof(IList <>)))
                {
                    Type listGenericType = property.Type.GetGenericArguments()[0];

                    var list = Activator.CreateInstance(typeof(List <>).MakeGenericType(listGenericType)) as IList;

                    if (list == null)
                    {
                        throw new ArgumentException($"property '{property.Name}' should be of type IList or IList<>");
                    }

                    string[]          columns = GetColumns(reader);
                    InterfaceMetadata propertyTypeMetadata = GetInterface(listGenericType);

                    ReadSingleResultset(reader, columns, list, propertyTypeMetadata);

                    property.SetValue(instance, list);
                }

                // if property type is interface then get one record from result set
                else if (property.Type.IsInterface && !property.Type.IsGenericType)
                {
                    if (reader.Read())
                    {
                        InterfaceMetadata interfaceType = GetInterface(property.Type);

                        object   value   = Activator.CreateInstance(interfaceType.Concrete);
                        string[] columns = GetColumns(reader);

                        ReadCurrentRow(reader, columns, value, interfaceType);

                        property.SetValue(instance, value);
                    }
                }
                // this case require a plain data type to work correctly
                else
                {
                    if (reader.Read())
                    {
                        property.SetValue(instance, ConvertType(reader[0], property.Type));
                    }
                }

                if (!reader.NextResult())
                {
                    break;
                }
            }
        }
Пример #6
0
        /// <summary>
        /// get entire result set from reader
        /// </summary>
        /// <param name="reader">data reader to read from</param>
        /// <param name="columns">data reader columns</param>
        /// <param name="list">list to save objects into</param>
        /// <param name="metaData">metadata for items in list</param>
        internal static void ReadSingleResultset(IDataReader reader, string[] columns, IList list, InterfaceMetadata metaData)
        {
            while (reader.Read())
            {
                object instance = Activator.CreateInstance(metaData.Concrete);

                ReadCurrentRow(reader, columns, instance, metaData);

                list.Add(instance);
            }
        }
Пример #7
0
        internal static void ReadCurrentRow(IDataReader reader, string[] columns, object instance, InterfaceMetadata metaData)
        {
            for (int i = 0; i < columns.Length; ++i)
            {
                object value = reader.GetValue(i);
                if (value is DBNull)
                {
                    continue;
                }

                PropertyMetadata property = metaData.GetProperty(columns[i], true);
                property?.SetValue(instance, ConvertType(value, property.Type));
            }
        }