日期:2014-05-16 浏览次数:20350 次
一直使用 MongoDb 的 Samus C#驱动。
其有一个缺陷,就是无法支持struct的读写。
但是一般数据都用Class包装,所以也没有太在意。
随着这些天尝试写入 KLineData 时,遇到了非常龌龊的问题。
KLineData这个Class内部有一个TICK[4] 这样一个数组,TICK是一个结构类型
Samus可以顺利的写入KLineData
但是读取时,立刻发生了异常。
查看内部实现,发现其用Emit做的ORM,代码如下:
1.创建Map
private ExtendedPropertiesMap CreateExtendedPropertiesMap(Type classType){ var extPropMember = _profile.FindExtendedPropertiesMember(classType); if(extPropMember == null) return null; return new ExtendedPropertiesMap( extPropMember.Name, extPropMember.GetReturnType(), MemberReflectionOptimizer.GetGetter(extPropMember), MemberReflectionOptimizer.GetSetter(extPropMember)); }其中GetSetter代码如下
public static Action<object, object> GetSetter(MemberInfo memberInfo) { if(memberInfo == null) throw new ArgumentNullException("memberInfo"); if(memberInfo.MemberType != MemberTypes.Field && memberInfo.MemberType != MemberTypes.Property) throw new ArgumentException("Only fields and properties are supported.", "memberInfo"); if(memberInfo.MemberType == MemberTypes.Field) return GetFieldSetter(memberInfo as FieldInfo); if(memberInfo.MemberType == MemberTypes.Property) return GetPropertySetter(memberInfo as PropertyInfo); throw new InvalidOperationException("Can only create setters for fields or properties."); }
public static Action<object, object> GetFieldSetter(FieldInfo fieldInfo) { if(fieldInfo == null) throw new ArgumentNullException("fieldInfo"); var key = CreateKey(fieldInfo); Action<object, object> setter; lock (SyncObject) { if (SetterCache.TryGetValue(key, out setter)) return setter; } if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral) throw new InvalidOperationException("Cannot create a setter for a readonly field."); var sourceType = fieldInfo.DeclaringType; var method = new DynamicMethod("Set" + fieldInfo.Name, null, new[] {typeof (object), typeof (object)}, true); var gen = method.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, sourceType); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); gen.Emit(OpCodes.Stfld, fieldInfo); gen.Emit(OpCodes.Ret); setter = (Action<object, object>) method.CreateDelegate(typeof (Action<object, object>)); lock (SyncObject) { SetterCache[key] = setter; } return setter; }gen.Emit(OpCodes.Ldarg_0); // 把参数0入栈