/// <summary> /// 访问表示方法调用的节点 /// </summary> /// <param name="node">方法调用节点</param> /// <returns></returns> public virtual Expression VisitMethodCall(MethodCallExpression node) { if (_typeRuntime == null) { _typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(this.GetType(), true); } MemberInvokerBase invoker = _typeRuntime.GetInvoker("Visit" + node.Method.Name); if (invoker == null) { throw new XFrameworkException("{0}.{1} is not supported.", node.Method.DeclaringType, node.Method.Name); } else { object exp = invoker.Invoke(this, new object[] { node }); return(exp as Expression); } }
/// <summary> /// 获取指定成员的 <see cref="ColumnAttribute"/> /// </summary> /// <param name="member">成员</param> /// <param name="objType">成员所在类型</param> /// <returns></returns> public virtual ColumnAttribute GetColumnAttribute(MemberInfo member, Type objType) { Type dataType = TypeUtils.GetDataType(member); if (dataType == null) { return(null); } ColumnAttribute column = null; Type type = objType != null ? objType : (member.ReflectedType != null ? member.ReflectedType : member.DeclaringType); if (type != null && !TypeUtils.IsAnonymousType(type) && !TypeUtils.IsPrimitiveType(type)) { TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); var invoker = typeRuntime.GetInvoker(member.Name); if (invoker != null) { column = invoker.Column; } } return(column); }
// 反序列化导航属性 // @prevLine 前一行数据 // @isLine 是否同一行数据<同一父级> void Deserialize_Navigation(object prevModel, object model, string typeName, bool isThisLine) { // CRM_SaleOrder.Client // CRM_SaleOrder.Client.AccountList Type type = model.GetType(); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); if (string.IsNullOrEmpty(typeName)) { typeName = type.Name; } foreach (var kvp in _map.Navigations) { int start = -1; int end = -1; var navigation = kvp.Value; if (navigation.FieldCount > 0) { start = navigation.Start; end = navigation.Start + navigation.FieldCount; } string keyName = typeName + "." + navigation.Name; if (keyName != kvp.Key) { continue; } var navInvoker = typeRuntime.GetInvoker(navigation.Name); if (navInvoker == null) { continue; } Type navType = navInvoker.DataType; Func <IDataRecord, object> deserializer = null; TypeRuntimeInfo navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navType); object navCollection = null; //if (navType.IsGenericType && navTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(navType)) { // 1:n关系,导航属性为 List<T> navCollection = navInvoker.Invoke(model); if (navCollection == null) { // new 一个列表类型,如果导航属性定义为接口,则默认使用List<T>来实例化 TypeRuntimeInfo navTypeRuntime2 = navType.IsInterface ? TypeRuntimeInfoCache.GetRuntimeInfo(typeof(List <>).MakeGenericType(navTypeRuntime.GenericArguments[0])) : navTypeRuntime; navCollection = navTypeRuntime2.ConstructInvoker.Invoke(); navInvoker.Invoke(model, navCollection); } } if (!_deserializers.TryGetValue(keyName, out deserializer)) { deserializer = _deserializerImpl.GetTypeDeserializer(navType.IsGenericType ? navTypeRuntime.GenericArguments[0] : navType, _reader, _map.PickColumns, start, end); _deserializers[keyName] = deserializer; } // 如果整个导航链中某一个导航属性为空,则跳出递归 object navModel = deserializer(_reader); if (navModel != null) { if (navCollection == null) { // 非集合型导航属性 navInvoker.Invoke(model, navModel); // // // } else { // 集合型导航属性 if (prevModel != null && isThisLine) { #region 合并列表 // 判断如果属于同一个主表,则合并到上一行的当前明细列表 // 例:CRM_SaleOrder.Client.AccountList string[] keys = keyName.Split('.'); TypeRuntimeInfo curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo <T>(); Type curType = curTypeRuntime.Type; MemberInvokerBase curInvoker = null; object curModel = prevModel; for (int i = 1; i < keys.Length; i++) { curInvoker = curTypeRuntime.GetInvoker(keys[i]); curModel = curInvoker.Invoke(curModel); if (curModel == null) { continue; } curType = curModel.GetType(); curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); // <<<<<<<<<<< 一对多对多关系 >>>>>>>>>> if (curType.IsGenericType && i != keys.Length - 1) { curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curType); //if (curTypeRuntime.GenericTypeDefinition == typeof(List<>)) if (TypeUtils.IsCollectionType(curType)) { var invoker = curTypeRuntime.GetInvoker("get_Count"); int count = Convert.ToInt32(invoker.Invoke(curModel)); // List.Count if (count > 0) { var invoker2 = curTypeRuntime.GetInvoker("get_Item"); curModel = invoker2.Invoke(curModel, count - 1); // List[List.Count-1] curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(curModel.GetType()); } else { // user.Roles.RoleFuncs=>Roles 列表有可能为空 curModel = null; break; } } } } if (curModel != null) { // 如果有两个以上的一对多关系的导航属性,那么在加入列表之前就需要剔除重复的实体 bool isAny = false; if (_map.Navigations.Count > 1) { if (_manyNavigationNumber == null) { _manyNavigationNumber = _map.Navigations.Count(x => IsHasMany(x.Value.Member)); } if (_manyNavigationNumber != null && _manyNavigationNumber.Value > 1) { if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var invoker in curTypeRuntime.KeyInvokers) { var value = invoker.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", invoker.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (_manyNavigationKeys[keyName].Contains(hash)) { isAny = true; } else { _manyNavigationKeys[keyName].Add(hash); } } } if (!isAny) { // 如果列表中不存在,则添加到上一行的相同导航列表中去 var myAddMethod = navTypeRuntime.GetInvoker("Add"); myAddMethod.Invoke(curModel, navModel); } } #endregion } else { // 此时的 navTypeRuntime 是 List<> 类型的运行时 // 先添加 List 列表 var myAddMethod = navTypeRuntime.GetInvoker("Add"); myAddMethod.Invoke(navCollection, navModel); var curTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navModel.GetType()); StringBuilder keyBuilder = new StringBuilder(64); foreach (var invoker in curTypeRuntime.KeyInvokers) { var value = invoker.Invoke(navModel); keyBuilder.AppendFormat("{0}={1};", invoker.Name, (value ?? string.Empty).ToString()); } string hash = keyBuilder.ToString(); if (!_manyNavigationKeys.ContainsKey(keyName)) { _manyNavigationKeys[keyName] = new HashSet <string>(); } if (!_manyNavigationKeys[keyName].Contains(hash)) { _manyNavigationKeys[keyName].Add(hash); } } } //if (navTypeRuntime.GenericTypeDefinition == typeof(List<>)) navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); if (TypeUtils.IsCollectionType(navTypeRuntime.Type)) { navTypeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(navTypeRuntime.GenericArguments[0]); } if (navTypeRuntime.NavInvokers.Count > 0) { Deserialize_Navigation(prevModel, navModel, keyName, isThisLine); } } } }
//static ConstructorInfo _ctorXmlReader = typeof(XmlTextReader).GetConstructor(new[] { typeof(string), typeof(XmlNodeType), typeof(XmlParserContext) }); //static ConstructorInfo _ctorSqlXml = typeof(System.Data.SqlTypes.SqlXml).GetConstructor(new[] { typeof(System.Xml.XmlTextReader) }); internal static Func <IDataRecord, object> GetTypeDeserializer(Type type, IDataRecord reader, IDictionary <string, Column> columns = null, int start = 0, int?end = null) { //// specify a new assembly name //var assemblyName = new AssemblyName("Kitty"); //// create assembly builder //var assemblyBuilder = AppDomain.CurrentDomain // .DefineDynamicAssembly(assemblyName, // AssemblyBuilderAccess.RunAndSave); //// create module builder //var moduleBuilder = // assemblyBuilder.DefineDynamicModule( // "KittyModule", "Kitty.exe"); //// create type builder for a class //var typeBuilder = // moduleBuilder.DefineType( // "HelloKittyClass", TypeAttributes.Public); //// create method builder //var methodBuilder = typeBuilder.DefineMethod( // "SayHelloMethod", // MethodAttributes.Public | MethodAttributes.Static, // typeof(object), // new Type[] { typeof(IDataRecord) }); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); DynamicMethod method = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(IDataRecord) }, true); //ILGenerator il = methodBuilder.GetILGenerator(); ILGenerator il = method.GetILGenerator(); il.DeclareLocal(typeof(int)); il.DeclareLocal(type); il.DeclareLocal(typeof(object)); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_2); // 有参构造函数 ConstructorInfo specializedConstructor = null; if (type.IsValueType) { // 如果是值类型,则将值类型设置为空或者0 il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Initobj, type); } else { var ctor = typeRuntime.ConstructInvoker.Constructor; if (ctor.GetParameters().Length > 0) { specializedConstructor = ctor; } else { // 如果不是匿名类或者只有无参构造函数,则new一个对象 il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Stloc_1); } } // try ##### il.BeginExceptionBlock(); if (specializedConstructor == null) { il.Emit(OpCodes.Ldloc_1); // [target] } // stack is now [target] Label finishLabel = il.DefineLabel(); Label loadNullLabel = il.DefineLabel(); int enumDeclareLocal = -1; if (end == null) { end = reader.FieldCount; } for (int index = start; index < end; index++) { // 找出对应DataReader中的字段名 string memberName = reader.GetName(index); if (columns != null) { Column column = null; columns.TryGetValue(memberName, out column); memberName = column != null ? column.Name : string.Empty; } // 本地变量赋值 il.Emit(OpCodes.Ldc_I4, index); // [target][index] il.Emit(OpCodes.Stloc_0); // [target] //il.Emit(OpCodes.Ldnull); // [target][null] //il.Emit(OpCodes.Stloc_2); // [target] // 如果导航属性分割列=DbNull,那么此导航属性赋空值 if (memberName == Constant.NAVIGATIONSPLITONNAME) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue_S, loadNullLabel); } var invoker = typeRuntime.GetInvoker(memberName); if (invoker == null) { continue; } if (specializedConstructor == null) { il.Emit(OpCodes.Dup); // stack is now [target][target] } Type columnType = reader.GetFieldType(index); Type memberType = invoker.DataType; Label isDbNullLabel = il.DefineLabel(); Label nextLoopLabel = il.DefineLabel(); MethodInfo readMethod = GetReaderMethod(columnType); // 判断字段是否是 DbNull il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue, isDbNullLabel); // =>DataReader.Getxx(index) il.Emit(OpCodes.Ldarg_0); // stack is now [target][target][reader] il.Emit(OpCodes.Ldc_I4, index); // stack is now [target][target][reader][index] il.Emit(OpCodes.Callvirt, readMethod); // stack is now [target][target][value-or-object] //// =>object = value,记录当前处理的值 //// 除了string类型之外,其它的都需要要装箱,这里会有性能损失,100w笔记录大概会损失0.8s~ //bool useBoxed = readMethod != _getValue && columnType != typeof(string); //il.Emit(OpCodes.Dup); // stack is now [target][target][value-or-object][value-or-object] //if (useBoxed) il.Emit(OpCodes.Box, columnType); // stack is now [target][target][value-or-object][value-as-object] //else il.Emit(OpCodes.Castclass, typeof(object)); // stack is now [target][target][value][value-as-object] //il.Emit(OpCodes.Stloc_2); // stack is now [target][target][value-or-object] if (memberType == typeof(char) || memberType == typeof(char?)) { il.EmitCall(OpCodes.Call, memberType == typeof(char) ? _readChar : _readNullChar, null); // stack is now [target][target][typed-value] } else { // unbox nullable enums as the primitive, i.e. byte etc var nullUnderlyingType = Nullable.GetUnderlyingType(memberType); var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : memberType; if (unboxType.IsEnum) { Type numericType = Enum.GetUnderlyingType(unboxType); if (columnType != typeof(string)) { BoxConvert(il, columnType, unboxType, numericType); } else { if (enumDeclareLocal == -1) { enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex; } il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [target][target][string] il.StoreLocal(enumDeclareLocal); // stack is now [target][target] il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][enum-type-token] il.EmitCall(OpCodes.Call, _typeFromHandle, null); // stack is now [target][target][enum-type] il.LoadLocal(enumDeclareLocal); // stack is now [target][target][enum-type][string] il.Emit(OpCodes.Ldc_I4_1); // stack is now [target][target][enum-type][string][true] il.EmitCall(OpCodes.Call, _enumParse, null); // stack is now [target][target][enum-as-object] il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value] } if (nullUnderlyingType != null) { var ctor = memberType.GetConstructor(new[] { nullUnderlyingType }); il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][typed-value] } } else if (memberType.FullName == _linqBinaryName) { var ctor = memberType.GetConstructor(new Type[] { typeof(byte[]) }); il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][target][byte-array] il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][binary] } else { TypeCode dataTypeCode = Type.GetTypeCode(columnType), unboxTypeCode = Type.GetTypeCode(unboxType); bool useOriginal = columnType == unboxType || dataTypeCode == unboxTypeCode || dataTypeCode == Type.GetTypeCode(nullUnderlyingType); // fix issue# oracle guid useOriginal = useOriginal && !((nullUnderlyingType ?? unboxType) == typeof(Guid) && columnType == typeof(byte[])); if (useOriginal) { if (readMethod == _getValue && unboxType != typeof(object)) { il.EmitCast(nullUnderlyingType ?? unboxType); // stack is now [target][target][typed-value] } } else { if (readMethod == _getValue && columnType.IsValueType)// stack is now [target][target][value] { il.Emit(OpCodes.Unbox_Any, columnType); } // not a direct match; need to tweak the unbox BoxConvert(il, columnType, nullUnderlyingType ?? unboxType, null); } if (nullUnderlyingType != null) { var ctor = unboxType.GetConstructor(new[] { nullUnderlyingType }); il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][typed-value] } } } if (specializedConstructor == null) { // Store the value in the property/field if (invoker.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Stfld, invoker.Member as FieldInfo); // stack is now [target] } else { MethodInfo setMethod = (invoker as PropertyInvoker).SetMethod; il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, setMethod);// stack is now [target] } } il.Emit(OpCodes.Br_S, nextLoopLabel); // stack is now [target] il.MarkLabel(isDbNullLabel); // incoming stack: [target][target] if (specializedConstructor == null) { il.Emit(OpCodes.Pop); // stack is now [target] } else { // DbNull,将NULL或者0推到栈顶 if (!invoker.DataType.IsValueType) { il.Emit(OpCodes.Ldnull); } else { int localIndex = il.DeclareLocal(invoker.DataType).LocalIndex; il.LoadLocalAddress(localIndex); il.Emit(OpCodes.Initobj, invoker.DataType); il.LoadLocal(localIndex); } } il.MarkLabel(nextLoopLabel); } if (specializedConstructor != null) { il.Emit(OpCodes.Newobj, specializedConstructor); } il.Emit(OpCodes.Stloc_1); // stack is empty // 直接跳到结束标签返回实体 il.Emit(OpCodes.Br, finishLabel); // 将 null 赋值给实体 il.MarkLabel(loadNullLabel); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_1); il.MarkLabel(finishLabel); il.BeginCatchBlock(typeof(Exception)); // stack is Exception il.Emit(OpCodes.Ldloc_0); // stack is Exception, index il.Emit(OpCodes.Ldloc_2); // stack is Exception, index, value il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader il.EmitCall(OpCodes.Call, _throwException, null); il.EndExceptionBlock(); il.Emit(OpCodes.Ldloc_1); // stack is [rval] il.Emit(OpCodes.Ret); //// then create the whole class type //var helloKittyClassType = typeBuilder.CreateType(); //// set entry point for this assembly //assemblyBuilder.SetEntryPoint( // helloKittyClassType.GetMethod("SayHelloMethod")); //// save assembly //assemblyBuilder.Save("Kitty.exe"); return((Func <IDataRecord, object>)method.CreateDelegate(typeof(Func <IDataRecord, object>))); }