MongoDb Samus 驱动的改进
一直使用 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.");
- }
我们关注其中的Field的Emit反射
- 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入栈
gen.Emit(OpCodes.Castclass, sourceType);//把参数0的类型转为sourceType : x as NewType
gen.Emit(OpCodes.Ldarg_1);// 把参数1入栈
gen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);//把参数1的类型强制转换为FieldType: (NewType)x
gen.Emit(OpCodes.Stfld, fieldInfo);// SetField( 参数0,参数1 )
gen.Emit(OpCodes.Ret);// 返回
以上代码有一个问题,就是要求参数0是Class,如果是Value是有异常的,即使可行也是没有意义的,因为ValueType是指传递
setter函数的设计模式(<object,object>) 天然就无法处理Value
解决办法:
- public void AddProperty(string name, object value)
- {
- #region Original Codes
- //var memberMap = _classMap.GetMemberMapFromAlias(name);
- //if (memberMap != null)
- // memberMap.SetValue(_instance, value);
- //else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
- // _extendedProperties.Add(name, value);
- #endregion
- #region norsd Codes
- if(_bIsClass)
- {
- var memberMap = _classMap.GetMemberMapFromAlias(name);
- if (memberMap != null)
- memberMap.SetValue(_instance, value);
- else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
- _extendedProperties.Add(name, value);
- }
- else
- {
- _SetStructValue(name, ref _instance, value);
- }
- #endregion
- }
注意_bIsClass就走原始流程,如果是Struct就走 _SetStructValue 流程
下面贴出整个类的代码
架构:
设置一个全局静态变量
readonly static System.Collections.Generic.Dictionary<System.Reflection.FieldInfo, SETSTVALUE> _s_dtStSetter = new Dictionary<System.Reflection.FieldInfo, SETSTVALUE>();
用于缓存SetStructValue函数
同时一个类私有变量readonly System.Collections.Generic.Dictionary<string, SETSTVALUE> _dtStSetter = new Dictionary<string, SETSTVALUE>();
用于快速在FieldInfo.Name -> SetStructValue
_CreateStSetter是动态创建函数
- using System;
- using MongoDB.Configuration.Mapping.Model;
- using System.Collections.Generic;
- namespace MongoDB.Serialization.Builders
- {
- internal class ConcreteClassMapBuilder : IObjectBuilder
- {
- private readonly IClassMap _classMap;
- #region Original
- //private readonly object _instance;
- #endregion
- #region norsd
- //由于struct需要装箱拆箱,_instance无法设为Null
- private object _instance = null;
- #endregion
- private readonly IDictionary<string, object> _extendedProperties;
- public ConcreteClassMapBuilder(IClassMap classMap)
- {
- _classMap = classMap;
- _instance = classMap.CreateInstance();
- #region norsd
- _bIsClass = _instance.GetType().IsClass;
- if (!_bIsClass)
- {
- var fields = _instance.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
- foreach (var fi in fields)
- {
- SETSTVALUE setter = null;
- _s_dtStSetter.TryGetValue(fi, out setter);
- if(setter == null)
- {
- setter = _CreateStSetter(_instance.GetType(),fi);
- if(null == setter)
- continue;
- _s_dtStSetter.Add(fi, setter);
- }
- _dtStSetter.Add(fi.Name, setter);
- }
- }
- #endregion
- if(!_classMap.HasExtendedProperties)
- return;
- var extPropType = _classMap.ExtendedPropertiesMap.MemberReturnType;
- if (extPropType == typeof(IDictionary<string, object>))
- extPropType = typeof(Dictionary<string, object>);
- _extendedProperties = (IDictionary<string, object>)Activator.CreateInstance(extPropType);
- _classMap.ExtendedPropertiesMap.SetValue(_instance, _extendedProperties);
- }
- public void AddProperty(string name, object value)
- {
- #region Original Codes
- //var memberMap = _classMap.GetMemberMapFromAlias(name);
- //if (memberMap != null)
- // memberMap.SetValue(_instance, value);
- //else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
- // _extendedProperties.Add(name, value);
- #endregion
- #region norsd Codes
- if(_bIsClass)
- {
- var memberMap = _classMap.GetMemberMapFromAlias(name);
- if (memberMap != null)
- memberMap.SetValue(_instance, value);
- else if ((!_classMap.HasDiscriminator || _classMap.DiscriminatorAlias != name) && _extendedProperties != null)
- _extendedProperties.Add(name, value);
- }
- else
- {
- _SetStructValue(name, ref _instance, value);
- }
- #endregion
- }
- public object BuildObject()
- {
- return _instance;
- }
- public PropertyDescriptor GetPropertyDescriptor(string name)
- {
- var memberMap = _classMap.GetMemberMapFromAlias(name);
- if (memberMap == null)
- return null;
- var type = memberMap.MemberReturnType;
- var isDictionary = false;
- if (memberMap is CollectionMemberMap)
- type = ((CollectionMemberMap)memberMap).ElementType;
- else if (memberMap is DictionaryMemberMap)
- {
- type = ((DictionaryMemberMap)memberMap).ValueType;
- isDictionary = true;
- }
- return new PropertyDescriptor { Type = type, IsDictionary = isDictionary };
- }
- #region norsd
- delegate void SETSTVALUE(ref object instance, object value);
- void _SetStructValue(string arg_strName , ref object arg_rInstance , object value)
- {
- SETSTVALUE setter = null;
- _dtStSetter.TryGetValue(arg_strName ,out setter);
- if (setter == null)
- {
- //throw new NotImplementedException();
- }
- else
- {
- setter(ref arg_rInstance, value);
- }
- }
- SETSTVALUE _CreateStSetter(Type arg_sourceType, System.Reflection.FieldInfo arg_fieldinfo)
- {
- var sourceType = arg_sourceType;
- var fieldInfo = arg_fieldinfo;
- var method2 = new System.Reflection.Emit.DynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(object).MakeByRefType(), typeof(object) }, true);
- var g = method2.GetILGenerator();
- var local = g.DeclareLocal(sourceType, true);
- g.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
- g.Emit(System.Reflection.Emit.OpCodes.Ldind_Ref);
- g.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, sourceType);
- g.Emit(System.Reflection.Emit.OpCodes.Stloc_0);//将前面Load的数据Set到Local 0
- g.Emit(System.Reflection.Emit.OpCodes.Ldloca_S, local);
- g.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
- g.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, fieldInfo.FieldType);
- g.Emit(System.Reflection.Emit.OpCodes.Stfld, fieldInfo);
- g.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
- g.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
- g.Emit(System.Reflection.Emit.OpCodes.Box, sourceType);
- g.Emit(System.Reflection.Emit.OpCodes.Stind_Ref);
- g.Emit(System.Reflection.Emit.OpCodes.Ret);
- var setter = (SETSTVALUE)method2.CreateDelegate(typeof(SETSTVALUE));
- return setter;
- }
- bool _bIsClass = false;
- readonly System.Collections.Generic.Dictionary<string, SETSTVALUE> _dtStSetter = new Dictionary<string, SETSTVALUE>();
- //全局缓存,
- readonly static System.Collections.Generic.Dictionary<System.Reflection.FieldInfo, SETSTVALUE> _s_dtStSetter = new Dictionary<System.Reflection.FieldInfo, SETSTVALUE>();
- #endregion
- }
- }
MongoDb Samus 驱动的改进的更多相关文章
- Mongodb的Samus驱动
最近开始学习Mongodb方面的东西.. 看到有很多博主都说MongoDB的第三方驱动 Samus 对Linq的支持比较好..能够降低学习的成本..所以就想从这里开始.. 但是弊端在我学习了一半的时候 ...
- 通过MongoDB的samus驱动实现基本数据操作
一.MongoDB的驱动 MongoDB支持多种语言的驱动: 在此我们只介绍 C# 的驱动.仅C#驱动都有很多种,每种驱动的形式大致相同,但是细节各有千秋,因此代码不能通用.比较常用的是官方驱动和sa ...
- MongoDB学习笔记(二) 通过samus驱动实现基本数据操作
传统的关系数据库一般由数据库(database).表(table).记录(record)三个层次概念组成,MongoDB是由(database).集合(collection).文档对象(documen ...
- MongoDB C#samus驱动
MongoDB的c#驱动有两种,官方驱动和samus驱动,不过我更喜欢samus驱动,因为samus驱动提供了丰富的linq操作. 官方驱动:https://github.com/mongodb/mo ...
- Samus驱动中的Document条件
今天要说一个东西就是Samus驱动里的 Document 和他的一个子类 Op 在Samus驱动的增删改查方法中都有这类的参数传递.. 大致的使用方法是这样.. MongoU.Find<Per ...
- 通过samus驱动实现基本数据操作
传统的关系数据库一般由数据库(database).表(table).记录(record)三个层次概念组成,MongoDB是由(database).集合(collection).文档对象(documen ...
- (转载)MongoDB C#驱动中Query几个方法
MongoDB C#驱动中Query几个方法 Query.All("name", "a", "b");//通过多个元素来匹配数组 Query ...
- 使用VS2010编译MongoDB C++驱动详解
最近为了解决IM消息记录的高速度写入.多文档类型支持的需求,决定使用MongoDB来解决. 考虑到MongoDB对VS版本要求较高,与我现有的VS版本不兼容,在leveldb.ssdb.redis.h ...
- MongoDB C#驱动:
MongoDB C#驱动: http://xiaosheng.me/2016/09/15/article24 http://www.cnblogs.com/wuhuacong/p/5098348.ht ...
随机推荐
- IOS开发之Iphone和Ipad应用程序图标和启动动画
本文转载至 http://blog.csdn.net/yesjava/article/details/8782060 当我们用xcode开发iphone和ipad应用程序的时候,我们可以用一下表中所显 ...
- mongoose在Windows Server 2003上不能访问问题的解决
这两天在部署EasyDarwin开源流媒体服务器到Windows Server 2003的时候,奇怪地发现,在Windows 2003上面,mongoose的web管理端口居然无法访问,但通过nets ...
- javascript --- 声明提前(学习笔记)
声明提升 未声明变量 console.log(a); 在没有定义 a 的情况下,直接使用,会报错. 声明变量 console.log(a); var a = 2; 输出结果:undefined 并不会 ...
- 在MFC中使用大漠插件
打开Class Wizard,Add Class...->MFC Class From TypeLib... File->Location->>> Finish-> ...
- PAT 天梯赛 L2-013. 红色警报 【BFS】
题目链接 https://www.patest.cn/contests/gplt/L2-013 思路 可以通过图的连通块个数来判断 假如 一座城市的失去 改变了其他城市之间的连通性 那么 这座城市本来 ...
- UIView封装动画--iOS利用系统提供方法来做关键帧动画
iOS利用系统提供方法来做关键帧动画 ios7以后才有用. /*关键帧动画 options:UIViewKeyframeAnimationOptions类型 */ [UIView animateKey ...
- 搭建iis本地测试服务器
在“开始”选择 “控制面板”,默认是以“类别”显示, 改成“小图标”显示 选择“程序和功能” 进入界面后,点击“启动或关闭Windows功能” 然后勾选图中的两个选框,注意一定要显示为 ...
- hive和hbase本质区别——hbase本质是OLTP的nosql DB,而hive是OLAP 底层是hdfs,需从已有数据库同步数据到hdfs;hive可以用hbase中的数据,通过hive表映射到hbase表
对于hbase当前noSql数据库的一种,最常见的应用场景就是采集的网页数据的存储,由于是key-value型数据库,可以再扩展到各种key-value应用场景,如日志信息的存储,对于内容信息不需要完 ...
- Pyhton:汉诺塔游戏
#汉诺塔游戏攻略! def hanoi(n,x,y,z): if n == 1: print(x,'-->',z) else: hanoi(n-1,x,z,y) #将前n-1个盘子从x移动到y上 ...
- 【转载】rageagainstthecage.c源码以及注释
如下: //头文件包含 #include <stdio.h> #include <sys/types.h> #include <sys/time.h> #inclu ...